Merge git://git.kernel.org/pub/scm/linux/kernel/git/bunk/trivial
authorLinus Torvalds <torvalds@g5.osdl.org>
Sat, 25 Mar 2006 16:41:09 +0000 (08:41 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sat, 25 Mar 2006 16:41:09 +0000 (08:41 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/bunk/trivial: (21 commits)
  BUG_ON() Conversion in drivers/video/
  BUG_ON() Conversion in drivers/parisc/
  BUG_ON() Conversion in drivers/block/
  BUG_ON() Conversion in sound/sparc/cs4231.c
  BUG_ON() Conversion in drivers/s390/block/dasd.c
  BUG_ON() Conversion in lib/swiotlb.c
  BUG_ON() Conversion in kernel/cpu.c
  BUG_ON() Conversion in ipc/msg.c
  BUG_ON() Conversion in block/elevator.c
  BUG_ON() Conversion in fs/coda/
  BUG_ON() Conversion in fs/binfmt_elf_fdpic.c
  BUG_ON() Conversion in input/serio/hil_mlc.c
  BUG_ON() Conversion in md/dm-hw-handler.c
  BUG_ON() Conversion in md/bitmap.c
  The comment describing how MS_ASYNC works in msync.c is confusing
  rcu: undeclared variable used in documentation
  fix typos "wich" -> "which"
  typo patch for fs/ufs/super.c
  Fix simple typos
  tabify drivers/char/Makefile
  ...

576 files changed:
CREDITS
Documentation/feature-removal-schedule.txt
Documentation/filesystems/9p.txt [new file with mode: 0644]
Documentation/filesystems/udf.txt
Documentation/filesystems/v9fs.txt [deleted file]
Documentation/filesystems/vfs.txt
Documentation/firmware_class/firmware_sample_driver.c
Documentation/firmware_class/firmware_sample_firmware_class.c
Documentation/kernel-parameters.txt
Documentation/networking/ray_cs.txt
Documentation/serial-console.txt
Documentation/sound/oss/Introduction
Documentation/sound/oss/cs46xx
Documentation/video4linux/CQcam.txt
Documentation/video4linux/README.cpia
Documentation/video4linux/Zoran
Documentation/video4linux/bttv/ICs
Documentation/video4linux/bttv/PROBLEMS
Documentation/video4linux/bttv/README.quirks
Documentation/video4linux/bttv/THANKS
Documentation/video4linux/radiotrack.txt
Documentation/video4linux/w9966.txt
Documentation/video4linux/zr36120.txt
MAINTAINERS
arch/arm/mach-sa1100/collie.c
arch/i386/Kconfig
arch/i386/Kconfig.debug
arch/i386/boot/edd.S
arch/i386/kernel/dmi_scan.c
arch/i386/kernel/smpboot.c
arch/ia64/ia32/sys_ia32.c
arch/m32r/Kconfig.debug
arch/mips/kernel/sysirix.c
arch/ppc/8xx_io/cs4218_tdm.c
arch/sparc/Kconfig
arch/sparc/kernel/irq.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/mm/srmmu.c
arch/sparc64/Kconfig.debug
arch/x86_64/ia32/sys_ia32.c
drivers/base/cpu.c
drivers/block/Kconfig
drivers/block/ataflop.c
drivers/block/floppy.c
drivers/block/nbd.c
drivers/cdrom/cm206.c
drivers/cdrom/sbpcd.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/istallion.c
drivers/char/mem.c
drivers/char/mxser.c
drivers/char/ppdev.c
drivers/char/riscom8.c
drivers/char/sysrq.c
drivers/char/tpm/tpm.h
drivers/char/tty_io.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/ep93xx_wdt.c [new file with mode: 0644]
drivers/dio/dio-driver.c
drivers/eisa/.gitignore [new file with mode: 0644]
drivers/eisa/eisa-bus.c
drivers/ide/ide.c
drivers/input/touchscreen/ads7846.c
drivers/isdn/hardware/avm/b1dma.c
drivers/isdn/hardware/avm/b1isa.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/avm/t1isa.c
drivers/isdn/hysdn/boardergo.c
drivers/isdn/hysdn/boardergo.h
drivers/isdn/hysdn/hycapi.c
drivers/isdn/hysdn/hysdn_boot.c
drivers/isdn/hysdn/hysdn_defs.h
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/hysdn/hysdn_net.c
drivers/isdn/hysdn/hysdn_pof.h
drivers/isdn/hysdn/hysdn_procconf.c
drivers/isdn/hysdn/hysdn_proclog.c
drivers/isdn/hysdn/hysdn_sched.c
drivers/isdn/hysdn/ince1pc.h
drivers/isdn/i4l/isdn_ppp.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/isdnloop/isdnloop.c
drivers/md/bitmap.c
drivers/media/Kconfig
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/flexcop-usb.c
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/cxusb.h
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/arv.c
drivers/media/video/bt819.c
drivers/media/video/bt832.c [deleted file]
drivers/media/video/bt832.h [deleted file]
drivers/media/video/bt848.h [deleted file]
drivers/media/video/bt856.c
drivers/media/video/bt8xx/Kconfig [new file with mode: 0644]
drivers/media/video/bt8xx/Makefile [new file with mode: 0644]
drivers/media/video/bt8xx/bt832.c [new file with mode: 0644]
drivers/media/video/bt8xx/bt832.h [new file with mode: 0644]
drivers/media/video/bt8xx/bt848.h [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-cards.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-driver.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-gpio.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-i2c.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-if.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-input.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-risc.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-vbi.c [new file with mode: 0644]
drivers/media/video/bt8xx/bttv.h [new file with mode: 0644]
drivers/media/video/bt8xx/bttvp.h [new file with mode: 0644]
drivers/media/video/bttv-cards.c [deleted file]
drivers/media/video/bttv-driver.c [deleted file]
drivers/media/video/bttv-gpio.c [deleted file]
drivers/media/video/bttv-i2c.c [deleted file]
drivers/media/video/bttv-if.c [deleted file]
drivers/media/video/bttv-input.c [deleted file]
drivers/media/video/bttv-risc.c [deleted file]
drivers/media/video/bttv-vbi.c [deleted file]
drivers/media/video/bttv.h [deleted file]
drivers/media/video/bttvp.h [deleted file]
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia.h
drivers/media/video/cpia2/cpia2.h
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cpia_pp.c
drivers/media/video/cpia_usb.c
drivers/media/video/cs53l32a.c
drivers/media/video/cs8420.h
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-vbi.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dabfirmware.h [new file with mode: 0644]
drivers/media/video/dabusb.c [new file with mode: 0644]
drivers/media/video/dabusb.h [new file with mode: 0644]
drivers/media/video/dsbr100.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/et61x251/Makefile [new file with mode: 0644]
drivers/media/video/et61x251/et61x251.h [new file with mode: 0644]
drivers/media/video/et61x251/et61x251_core.c [new file with mode: 0644]
drivers/media/video/et61x251/et61x251_sensor.h [new file with mode: 0644]
drivers/media/video/et61x251/et61x251_tas5130d1b.c [new file with mode: 0644]
drivers/media/video/font.h [new file with mode: 0644]
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-driver.h [new file with mode: 0644]
drivers/media/video/msp3400-kthreads.c
drivers/media/video/msp3400.h [deleted file]
drivers/media/video/mxb.c
drivers/media/video/ov511.c [new file with mode: 0644]
drivers/media/video/ov511.h [new file with mode: 0644]
drivers/media/video/ovcamchip/Makefile
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/ovcamchip/ovcamchip_priv.h
drivers/media/video/planb.c
drivers/media/video/planb.h
drivers/media/video/pms.c
drivers/media/video/pwc/Makefile [new file with mode: 0644]
drivers/media/video/pwc/philips.txt [new file with mode: 0644]
drivers/media/video/pwc/pwc-ctrl.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-if.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-ioctl.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-kiara.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-kiara.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-misc.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-nala.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-timon.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-timon.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-uncompress.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-uncompress.h [new file with mode: 0644]
drivers/media/video/pwc/pwc.h [new file with mode: 0644]
drivers/media/video/rds.h [deleted file]
drivers/media/video/saa5249.c
drivers/media/video/saa6588.c
drivers/media/video/saa7110.c
drivers/media/video/saa7111.c
drivers/media/video/saa7114.c
drivers/media/video/saa7115.c
drivers/media/video/saa7121.h
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-oss.c
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-vbi.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7146.h
drivers/media/video/saa7146reg.h
drivers/media/video/saa7185.c
drivers/media/video/saa7196.h
drivers/media/video/se401.c [new file with mode: 0644]
drivers/media/video/se401.h [new file with mode: 0644]
drivers/media/video/sn9c102/Makefile [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102.h [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_core.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_hv7131d.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_mi0343.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_ov7630.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas106b.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas202bca.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas202bcb.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_sensor.h [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_tas5110c1b.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_tas5130d1b.c [new file with mode: 0644]
drivers/media/video/stradis.c
drivers/media/video/stv680.c [new file with mode: 0644]
drivers/media/video/stv680.h [new file with mode: 0644]
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tda9840.h
drivers/media/video/tda9875.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tea6420.h
drivers/media/video/tuner-3036.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tvaudio.h [deleted file]
drivers/media/video/tveeprom.c
drivers/media/video/usbvideo/Makefile [new file with mode: 0644]
drivers/media/video/usbvideo/ibmcam.c [new file with mode: 0644]
drivers/media/video/usbvideo/konicawc.c [new file with mode: 0644]
drivers/media/video/usbvideo/ultracam.c [new file with mode: 0644]
drivers/media/video/usbvideo/usbvideo.c [new file with mode: 0644]
drivers/media/video/usbvideo/usbvideo.h [new file with mode: 0644]
drivers/media/video/usbvideo/vicam.c [new file with mode: 0644]
drivers/media/video/v4l2-common.c
drivers/media/video/video-buf.c
drivers/media/video/videocodec.h
drivers/media/video/vino.c
drivers/media/video/vivi.c [new file with mode: 0644]
drivers/media/video/vpx3220.c
drivers/media/video/w9966.c
drivers/media/video/w9968cf.c [new file with mode: 0644]
drivers/media/video/w9968cf.h [new file with mode: 0644]
drivers/media/video/w9968cf_decoder.h [new file with mode: 0644]
drivers/media/video/w9968cf_vpp.h [new file with mode: 0644]
drivers/media/video/wm8775.c
drivers/media/video/zc0301/Makefile [new file with mode: 0644]
drivers/media/video/zc0301/zc0301.h [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_core.c [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_pas202bcb.c [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_sensor.h [new file with mode: 0644]
drivers/media/video/zoran.h
drivers/media/video/zoran_card.c
drivers/media/video/zoran_card.h
drivers/media/video/zoran_device.c
drivers/media/video/zoran_device.h
drivers/media/video/zoran_driver.c
drivers/media/video/zoran_procfs.c
drivers/media/video/zoran_procfs.h
drivers/media/video/zr36016.c
drivers/media/video/zr36050.c
drivers/media/video/zr36057.h
drivers/media/video/zr36060.c
drivers/media/video/zr36120.c
drivers/media/video/zr36120.h
drivers/message/i2o/debug.c
drivers/mmc/au1xmmc.c
drivers/mtd/maps/pcmciamtd.c
drivers/net/3c59x.c
drivers/net/a2065.c
drivers/net/ariadne.c
drivers/net/arm/Kconfig
drivers/net/arm/Makefile
drivers/net/arm/at91_ether.c [new file with mode: 0644]
drivers/net/arm/at91_ether.h [new file with mode: 0644]
drivers/net/atari_bionet.c
drivers/net/atari_pamsnet.c
drivers/net/atarilance.c
drivers/net/cassini.c
drivers/net/chelsio/cxgb2.c
drivers/net/dgrs.c
drivers/net/fec_8xx/fec_main.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gt96100eth.c
drivers/net/hamradio/dmascc.c
drivers/net/hamradio/mkiss.c
drivers/net/hplance.c
drivers/net/hydra.c
drivers/net/irda/irport.c
drivers/net/lasi_82596.c
drivers/net/mac89x0.c
drivers/net/mace.c
drivers/net/meth.c
drivers/net/ne-h8300.c
drivers/net/ne2k-pci.c
drivers/net/ni5010.c
drivers/net/sun3lance.c
drivers/net/wireless/Kconfig
drivers/net/zorro8390.c
drivers/pnp/isapnp/core.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/scsi/arm/cumana_2.c
drivers/scsi/arm/eesox.c
drivers/scsi/arm/powertec.c
drivers/scsi/atari_scsi.c
drivers/scsi/sd.c
drivers/serial/8250_hp300.c
drivers/serial/ioc4_serial.c
drivers/serial/mpsc.c
drivers/serial/mpsc.h [deleted file]
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/media/Kconfig [deleted file]
drivers/usb/media/Makefile [deleted file]
drivers/usb/media/dabfirmware.h [deleted file]
drivers/usb/media/dabusb.c [deleted file]
drivers/usb/media/dabusb.h [deleted file]
drivers/usb/media/dsbr100.c [deleted file]
drivers/usb/media/et61x251.h [deleted file]
drivers/usb/media/et61x251_core.c [deleted file]
drivers/usb/media/et61x251_sensor.h [deleted file]
drivers/usb/media/et61x251_tas5130d1b.c [deleted file]
drivers/usb/media/ibmcam.c [deleted file]
drivers/usb/media/konicawc.c [deleted file]
drivers/usb/media/ov511.c [deleted file]
drivers/usb/media/ov511.h [deleted file]
drivers/usb/media/pwc/Makefile [deleted file]
drivers/usb/media/pwc/philips.txt [deleted file]
drivers/usb/media/pwc/pwc-ctrl.c [deleted file]
drivers/usb/media/pwc/pwc-if.c [deleted file]
drivers/usb/media/pwc/pwc-ioctl.h [deleted file]
drivers/usb/media/pwc/pwc-kiara.c [deleted file]
drivers/usb/media/pwc/pwc-kiara.h [deleted file]
drivers/usb/media/pwc/pwc-misc.c [deleted file]
drivers/usb/media/pwc/pwc-nala.h [deleted file]
drivers/usb/media/pwc/pwc-timon.c [deleted file]
drivers/usb/media/pwc/pwc-timon.h [deleted file]
drivers/usb/media/pwc/pwc-uncompress.c [deleted file]
drivers/usb/media/pwc/pwc-uncompress.h [deleted file]
drivers/usb/media/pwc/pwc.h [deleted file]
drivers/usb/media/se401.c [deleted file]
drivers/usb/media/se401.h [deleted file]
drivers/usb/media/sn9c102.h [deleted file]
drivers/usb/media/sn9c102_core.c [deleted file]
drivers/usb/media/sn9c102_hv7131d.c [deleted file]
drivers/usb/media/sn9c102_mi0343.c [deleted file]
drivers/usb/media/sn9c102_ov7630.c [deleted file]
drivers/usb/media/sn9c102_pas106b.c [deleted file]
drivers/usb/media/sn9c102_pas202bca.c [deleted file]
drivers/usb/media/sn9c102_pas202bcb.c [deleted file]
drivers/usb/media/sn9c102_sensor.h [deleted file]
drivers/usb/media/sn9c102_tas5110c1b.c [deleted file]
drivers/usb/media/sn9c102_tas5130d1b.c [deleted file]
drivers/usb/media/stv680.c [deleted file]
drivers/usb/media/stv680.h [deleted file]
drivers/usb/media/ultracam.c [deleted file]
drivers/usb/media/usbvideo.c [deleted file]
drivers/usb/media/usbvideo.h [deleted file]
drivers/usb/media/vicam.c [deleted file]
drivers/usb/media/w9968cf.c [deleted file]
drivers/usb/media/w9968cf.h [deleted file]
drivers/usb/media/w9968cf_decoder.h [deleted file]
drivers/usb/media/w9968cf_vpp.h [deleted file]
drivers/usb/media/zc0301.h [deleted file]
drivers/usb/media/zc0301_core.c [deleted file]
drivers/usb/media/zc0301_pas202bcb.c [deleted file]
drivers/usb/media/zc0301_sensor.h [deleted file]
drivers/video/backlight/locomolcd.c
drivers/video/cirrusfb.c
drivers/video/hpfb.c
drivers/video/pm3fb.c
drivers/zorro/zorro-driver.c
fs/9p/9p.c [deleted file]
fs/9p/9p.h
fs/9p/Makefile
fs/9p/conv.c
fs/9p/conv.h
fs/9p/debug.h
fs/9p/error.c
fs/9p/error.h
fs/9p/fcall.c [new file with mode: 0644]
fs/9p/fcprint.c [new file with mode: 0644]
fs/9p/fid.c
fs/9p/fid.h
fs/9p/mux.c
fs/9p/mux.h
fs/9p/trans_fd.c
fs/9p/trans_sock.c [deleted file]
fs/9p/transport.h
fs/9p/v9fs.c
fs/9p/v9fs.h
fs/9p/v9fs_vfs.h
fs/9p/vfs_addr.c
fs/9p/vfs_dentry.c
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/aio.c
fs/binfmt_elf.c
fs/binfmt_flat.c
fs/bio.c
fs/buffer.c
fs/char_dev.c
fs/compat.c
fs/dcache.c
fs/direct-io.c
fs/eventpoll.c
fs/exec.c
fs/ext2/super.c
fs/ext3/bitmap.c
fs/fs-writeback.c
fs/inode.c
fs/inotify.c
fs/jbd/journal.c
fs/jbd/transaction.c
fs/minix/bitmap.c
fs/minix/inode.c
fs/minix/itree_v1.c
fs/minix/itree_v2.c
fs/namei.c
fs/open.c
fs/pipe.c
fs/proc/proc_misc.c
fs/read_write.c
fs/reiserfs/file.c
fs/reiserfs/fix_node.c
fs/reiserfs/item_ops.c
fs/reiserfs/journal.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/reiserfs/xattr_acl.c
fs/smbfs/inode.c
fs/super.c
fs/udf/inode.c
include/asm-alpha/poll.h
include/asm-arm/arch-at91rm9200/at91rm9200_emac.h [new file with mode: 0644]
include/asm-arm/poll.h
include/asm-arm26/poll.h
include/asm-cris/poll.h
include/asm-frv/poll.h
include/asm-h8300/poll.h
include/asm-i386/poll.h
include/asm-ia64/poll.h
include/asm-m32r/poll.h
include/asm-m68k/poll.h
include/asm-mips/poll.h
include/asm-parisc/poll.h
include/asm-powerpc/poll.h
include/asm-s390/poll.h
include/asm-sh/poll.h
include/asm-sh64/poll.h
include/asm-sparc/cpudata.h
include/asm-sparc/poll.h
include/asm-sparc/smp.h
include/asm-sparc/spinlock.h
include/asm-sparc64/poll.h
include/asm-v850/poll.h
include/asm-x86_64/poll.h
include/asm-xtensa/poll.h
include/linux/bitops.h
include/linux/capability.h
include/linux/cpu.h
include/linux/cpumask.h
include/linux/dcache.h
include/linux/dio.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/i2c-id.h
include/linux/init.h
include/linux/inotify.h
include/linux/irq.h
include/linux/jbd.h
include/linux/kernel.h
include/linux/major.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/ppdev.h
include/linux/quota.h
include/linux/radix-tree.h
include/linux/reiserfs_fs.h
include/linux/reiserfs_xattr.h
include/linux/security.h
include/linux/slab.h
include/linux/time.h
include/linux/timex.h
include/linux/tty_flip.h
include/linux/udf_fs_i.h
include/linux/videodev2.h
include/linux/zorro.h
include/media/audiochip.h
include/media/cs53l32a.h [new file with mode: 0644]
include/media/i2c-addr.h [new file with mode: 0644]
include/media/msp3400.h [new file with mode: 0644]
include/media/rds.h [new file with mode: 0644]
include/media/saa7146_vv.h
include/media/tvaudio.h [new file with mode: 0644]
include/media/v4l2-common.h
include/media/video-buf.h
include/media/wm8775.h [new file with mode: 0644]
include/net/route.h
include/net/sock.h
include/video/pm3fb.h
init/Kconfig
init/initramfs.c
init/main.c
kernel/capability.c
kernel/irq/Makefile
kernel/irq/manage.c
kernel/irq/migration.c [new file with mode: 0644]
kernel/itimer.c
kernel/kthread.c
kernel/module.c
kernel/params.c
kernel/power/smp.c
kernel/rcutorture.c
kernel/softlockup.c
kernel/sys.c
kernel/time.c
kernel/timer.c
lib/Kconfig.debug
lib/Makefile
lib/cpumask.c [new file with mode: 0644]
lib/radix-tree.c
mm/Kconfig
mm/mmap.c
mm/page_alloc.c
mm/slab.c
mm/slob.c
mm/util.c
mm/vmscan.c
net/bluetooth/af_bluetooth.c
net/bridge/br_stp_bpdu.c
net/core/datagram.c
net/core/dev.c
net/core/skbuff.c
net/core/sock.c
net/dccp/proto.c
net/ipv4/icmp.c
net/ipv4/route.c
net/ipv4/tcp.c
net/netfilter/x_tables.c
net/rxrpc/main.c
net/sctp/input.c
net/sctp/socket.c
net/unix/af_unix.c
scripts/kallsyms.c
security/commoncap.c
security/keys/key.c
security/security.c
sound/oss/au1000.c
sound/oss/au1550_ac97.c
sound/oss/awe_wave.c
sound/oss/dmasound/dmasound_core.c
sound/oss/ite8172.c
sound/oss/sb_mixer.c
sound/oss/sequencer.c
sound/oss/swarm_cs4297a.c
sound/oss/waveartist.c

diff --git a/CREDITS b/CREDITS
index af70678a0afdf95ef720e7b35202eda1323a68c9..c6d69bf10e1513cf366ffe7e576ddb519433f869 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2007,13 +2007,14 @@ S: University of Stuttgart, Germany and
 S: Ecole Nationale Superieure des Telecommunications, Paris
 
 N: Jamie Lokier
-E: jamie@imbolc.ucc.ie
+E: jamie@shareable.org
+W: http://www.shareable.org/
 D: Reboot-through-BIOS for broken 486 motherboards
-D: Some parport fixes
-S: 11 Goodson Walk
-S: Marston
+D: Parport fixes, futex improvements
+D: First instruction of x86 sysenter path :)
+S: 51 Sunningwell Road
 S: Oxford
-S: OX3 0HX
+S: OX1 4SZ
 S: United Kingdom
 
 N: Mark Lord
index 21272e4b4a5c43bb79b0493954f2be58af4a34a1..495858b236b615a08a2824922c546fc1e2b13c9b 100644 (file)
@@ -176,6 +176,18 @@ Who:       Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@s
 
 ---------------------------
 
+What:  Usage of invalid timevals in setitimer
+When:  March 2007
+Why:   POSIX requires to validate timevals in the setitimer call. This
+       was never done by Linux. The invalid (e.g. negative timevals) were
+       silently converted to more or less random timeouts and intervals.
+       Until the removal a per boot limited number of warnings is printed
+       and the timevals are sanitized.
+
+Who:   Thomas Gleixner <tglx@linutronix.de>
+
+---------------------------
+
 What:  I2C interface of the it87 driver
 When:  January 2007
 Why:   The ISA interface is faster and should be always available. The I2C
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
new file mode 100644 (file)
index 0000000..43b89c2
--- /dev/null
@@ -0,0 +1,100 @@
+                   v9fs: Plan 9 Resource Sharing for Linux
+                   =======================================
+
+ABOUT
+=====
+
+v9fs is a Unix implementation of the Plan 9 9p remote filesystem protocol.
+
+This software was originally developed by Ron Minnich <rminnich@lanl.gov>
+and Maya Gokhale <maya@lanl.gov>.  Additional development by Greg Watson
+<gwatson@lanl.gov> and most recently Eric Van Hensbergen
+<ericvh@gmail.com>, Latchesar Ionkov <lucho@ionkov.net> and Russ Cox
+<rsc@swtch.com>.
+
+USAGE
+=====
+
+For remote file server:
+
+       mount -t 9p 10.10.1.2 /mnt/9
+
+For Plan 9 From User Space applications (http://swtch.com/plan9)
+
+       mount -t 9p `namespace`/acme /mnt/9 -o proto=unix,uname=$USER
+
+OPTIONS
+=======
+
+  proto=name   select an alternative transport.  Valid options are
+               currently:
+                       unix - specifying a named pipe mount point
+                       tcp  - specifying a normal TCP/IP connection
+                       fd   - used passed file descriptors for connection
+                                (see rfdno and wfdno)
+
+  uname=name   user name to attempt mount as on the remote server.  The
+               server may override or ignore this value.  Certain user
+               names may require authentication.
+
+  aname=name   aname specifies the file tree to access when the server is
+               offering several exported file systems.
+
+  debug=n      specifies debug level.  The debug level is a bitmask.
+                       0x01 = display verbose error messages
+                       0x02 = developer debug (DEBUG_CURRENT)
+                       0x04 = display 9p trace
+                       0x08 = display VFS trace
+                       0x10 = display Marshalling debug
+                       0x20 = display RPC debug
+                       0x40 = display transport debug
+                       0x80 = display allocation debug
+
+  rfdno=n      the file descriptor for reading with proto=fd
+
+  wfdno=n      the file descriptor for writing with proto=fd
+
+  maxdata=n    the number of bytes to use for 9p packet payload (msize)
+
+  port=n       port to connect to on the remote server
+
+  noextend     force legacy mode (no 9p2000.u semantics)
+
+  uid          attempt to mount as a particular uid
+
+  gid          attempt to mount with a particular gid
+
+  afid         security channel - used by Plan 9 authentication protocols
+
+  nodevmap     do not map special files - represent them as normal files.
+               This can be used to share devices/named pipes/sockets between
+               hosts.  This functionality will be expanded in later versions.
+
+RESOURCES
+=========
+
+The Linux version of the 9p server is now maintained under the npfs project
+on sourceforge (http://sourceforge.net/projects/npfs).
+
+There are user and developer mailing lists available through the v9fs project
+on sourceforge (http://sourceforge.net/projects/v9fs).
+
+News and other information is maintained on SWiK (http://swik.net/v9fs).
+
+Bug reports may be issued through the kernel.org bugzilla 
+(http://bugzilla.kernel.org)
+
+For more information on the Plan 9 Operating System check out
+http://plan9.bell-labs.com/plan9
+
+For information on Plan 9 from User Space (Plan 9 applications and libraries
+ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9
+
+
+STATUS
+======
+
+The 2.6 kernel support is working on PPC and x86.
+
+PLEASE USE THE SOURCEFORGE BUG-TRACKER TO REPORT PROBLEMS.
+
index e5213bc301f721a1c3236a4469194982c9653865..511b4230c0536add9d0650cbc1f702becc2e54e2 100644 (file)
@@ -26,6 +26,20 @@ The following mount options are supported:
        nostrict        Unset strict conformance
        iocharset=      Set the NLS character set
 
+The uid= and gid= options need a bit more explaining.  They will accept a
+decimal numeric value which will be used as the default ID for that mount.
+They will also accept the string "ignore" and "forget".  For files on the disk
+that are owned by nobody ( -1 ), they will instead look as if they are owned
+by the default ID.  The ignore option causes the default ID to override all
+IDs on the disk, not just -1.  The forget option causes all IDs to be written
+to disk as -1, so when the media is later remounted, they will appear to be
+owned by whatever default ID it is mounted with at that time.
+
+For typical desktop use of removable media, you should set the ID to that
+of the interactively logged on user, and also specify both the forget and
+ignore options.  This way the interactive user will always see the files
+on the disk as belonging to him.
+
 The remaining are for debugging and disaster recovery:
 
        novrs           Skip volume sequence recognition 
diff --git a/Documentation/filesystems/v9fs.txt b/Documentation/filesystems/v9fs.txt
deleted file mode 100644 (file)
index 24c7a9c..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-                       V9FS: 9P2000 for Linux
-                       ======================
-
-ABOUT
-=====
-
-v9fs is a Unix implementation of the Plan 9 9p remote filesystem protocol.
-
-This software was originally developed by Ron Minnich <rminnich@lanl.gov>
-and Maya Gokhale <maya@lanl.gov>.  Additional development by Greg Watson
-<gwatson@lanl.gov> and most recently Eric Van Hensbergen
-<ericvh@gmail.com> and Latchesar Ionkov <lucho@ionkov.net>.
-
-USAGE
-=====
-
-For remote file server:
-
-       mount -t 9P 10.10.1.2 /mnt/9
-
-For Plan 9 From User Space applications (http://swtch.com/plan9)
-
-       mount -t 9P `namespace`/acme /mnt/9 -o proto=unix,name=$USER
-
-OPTIONS
-=======
-
-  proto=name   select an alternative transport.  Valid options are
-               currently:
-                       unix - specifying a named pipe mount point
-                       tcp  - specifying a normal TCP/IP connection
-                       fd   - used passed file descriptors for connection
-                                (see rfdno and wfdno)
-
-  name=name    user name to attempt mount as on the remote server.  The
-               server may override or ignore this value.  Certain user
-               names may require authentication.
-
-  aname=name   aname specifies the file tree to access when the server is
-               offering several exported file systems.
-
-  debug=n      specifies debug level.  The debug level is a bitmask.
-                       0x01 = display verbose error messages
-                       0x02 = developer debug (DEBUG_CURRENT)
-                       0x04 = display 9P trace
-                       0x08 = display VFS trace
-                       0x10 = display Marshalling debug
-                       0x20 = display RPC debug
-                       0x40 = display transport debug
-                       0x80 = display allocation debug
-
-  rfdno=n      the file descriptor for reading with proto=fd
-
-  wfdno=n      the file descriptor for writing with proto=fd
-
-  maxdata=n    the number of bytes to use for 9P packet payload (msize)
-
-  port=n       port to connect to on the remote server
-
-  noextend     force legacy mode (no 9P2000.u semantics)
-
-  uid          attempt to mount as a particular uid
-
-  gid          attempt to mount with a particular gid
-
-  afid         security channel - used by Plan 9 authentication protocols
-
-  nodevmap     do not map special files - represent them as normal files.
-               This can be used to share devices/named pipes/sockets between
-               hosts.  This functionality will be expanded in later versions.
-
-RESOURCES
-=========
-
-The Linux version of the 9P server is now maintained under the npfs project
-on sourceforge (http://sourceforge.net/projects/npfs).
-
-There are user and developer mailing lists available through the v9fs project
-on sourceforge (http://sourceforge.net/projects/v9fs).
-
-News and other information is maintained on SWiK (http://swik.net/v9fs).
-
-Bug reports may be issued through the kernel.org bugzilla 
-(http://bugzilla.kernel.org)
-
-For more information on the Plan 9 Operating System check out
-http://plan9.bell-labs.com/plan9
-
-For information on Plan 9 from User Space (Plan 9 applications and libraries
-ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9
-
-
-STATUS
-======
-
-The 2.6 kernel support is working on PPC and x86.
-
-PLEASE USE THE SOURCEFORGE BUG-TRACKER TO REPORT PROBLEMS.
-
index e56e842847d3ee3e48c79b4099bc0d6040d730a1..adaa899e5c903763a4f0938efedd1bd3bbdce4a0 100644 (file)
@@ -230,10 +230,15 @@ only called from a process context (i.e. not from an interrupt handler
 or bottom half).
 
   alloc_inode: this method is called by inode_alloc() to allocate memory
-       for struct inode and initialize it.
+       for struct inode and initialize it.  If this function is not
+       defined, a simple 'struct inode' is allocated.  Normally
+       alloc_inode will be used to allocate a larger structure which
+       contains a 'struct inode' embedded within it.
 
   destroy_inode: this method is called by destroy_inode() to release
-       resources allocated for struct inode.
+       resources allocated for struct inode.  It is only required if
+       ->alloc_inode was defined and simply undoes anything done by
+       ->alloc_inode.
 
   read_inode: this method is called to read a specific inode from the
         mounted filesystem.  The i_ino member in the struct inode is
@@ -443,14 +448,81 @@ otherwise noted.
 The Address Space Object
 ========================
 
-The address space object is used to identify pages in the page cache.
-
+The address space object is used to group and manage pages in the page
+cache.  It can be used to keep track of the pages in a file (or
+anything else) and also track the mapping of sections of the file into
+process address spaces.
+
+There are a number of distinct yet related services that an
+address-space can provide.  These include communicating memory
+pressure, page lookup by address, and keeping track of pages tagged as
+Dirty or Writeback.
+
+The first can be used independently to the others.  The VM can try to
+either write dirty pages in order to clean them, or release clean
+pages in order to reuse them.  To do this it can call the ->writepage
+method on dirty pages, and ->releasepage on clean pages with
+PagePrivate set. Clean pages without PagePrivate and with no external
+references will be released without notice being given to the
+address_space.
+
+To achieve this functionality, pages need to be placed on an LRU with
+lru_cache_add and mark_page_active needs to be called whenever the
+page is used.
+
+Pages are normally kept in a radix tree index by ->index. This tree
+maintains information about the PG_Dirty and PG_Writeback status of
+each page, so that pages with either of these flags can be found
+quickly.
+
+The Dirty tag is primarily used by mpage_writepages - the default
+->writepages method.  It uses the tag to find dirty pages to call
+->writepage on.  If mpage_writepages is not used (i.e. the address
+provides its own ->writepages) , the PAGECACHE_TAG_DIRTY tag is
+almost unused.  write_inode_now and sync_inode do use it (through
+__sync_single_inode) to check if ->writepages has been successful in
+writing out the whole address_space.
+
+The Writeback tag is used by filemap*wait* and sync_page* functions,
+via wait_on_page_writeback_range, to wait for all writeback to
+complete.  While waiting ->sync_page (if defined) will be called on
+each page that is found to require writeback.
+
+An address_space handler may attach extra information to a page,
+typically using the 'private' field in the 'struct page'.  If such
+information is attached, the PG_Private flag should be set.  This will
+cause various VM routines to make extra calls into the address_space
+handler to deal with that data.
+
+An address space acts as an intermediate between storage and
+application.  Data is read into the address space a whole page at a
+time, and provided to the application either by copying of the page,
+or by memory-mapping the page.
+Data is written into the address space by the application, and then
+written-back to storage typically in whole pages, however the
+address_space has finer control of write sizes.
+
+The read process essentially only requires 'readpage'.  The write
+process is more complicated and uses prepare_write/commit_write or
+set_page_dirty to write data into the address_space, and writepage,
+sync_page, and writepages to writeback data to storage.
+
+Adding and removing pages to/from an address_space is protected by the
+inode's i_mutex.
+
+When data is written to a page, the PG_Dirty flag should be set.  It
+typically remains set until writepage asks for it to be written.  This
+should clear PG_Dirty and set PG_Writeback.  It can be actually
+written at any point after PG_Dirty is clear.  Once it is known to be
+safe, PG_Writeback is cleared.
+
+Writeback makes use of a writeback_control structure...
 
 struct address_space_operations
 -------------------------------
 
 This describes how the VFS can manipulate mapping of a file to page cache in
-your filesystem. As of kernel 2.6.13, the following members are defined:
+your filesystem. As of kernel 2.6.16, the following members are defined:
 
 struct address_space_operations {
        int (*writepage)(struct page *page, struct writeback_control *wbc);
@@ -469,47 +541,148 @@ struct address_space_operations {
                        loff_t offset, unsigned long nr_segs);
        struct page* (*get_xip_page)(struct address_space *, sector_t,
                        int);
+       /* migrate the contents of a page to the specified target */
+       int (*migratepage) (struct page *, struct page *);
 };
 
-  writepage: called by the VM write a dirty page to backing store.
+  writepage: called by the VM to write a dirty page to backing store.
+      This may happen for data integrity reasons (i.e. 'sync'), or
+      to free up memory (flush).  The difference can be seen in
+      wbc->sync_mode.
+      The PG_Dirty flag has been cleared and PageLocked is true.
+      writepage should start writeout, should set PG_Writeback,
+      and should make sure the page is unlocked, either synchronously
+      or asynchronously when the write operation completes.
+
+      If wbc->sync_mode is WB_SYNC_NONE, ->writepage doesn't have to
+      try too hard if there are problems, and may choose to write out
+      other pages from the mapping if that is easier (e.g. due to
+      internal dependencies).  If it chooses not to start writeout, it
+      should return AOP_WRITEPAGE_ACTIVATE so that the VM will not keep
+      calling ->writepage on that page.
+
+      See the file "Locking" for more details.
 
   readpage: called by the VM to read a page from backing store.
+       The page will be Locked when readpage is called, and should be
+       unlocked and marked uptodate once the read completes.
+       If ->readpage discovers that it needs to unlock the page for
+       some reason, it can do so, and then return AOP_TRUNCATED_PAGE.
+       In this case, the page will be relocated, relocked and if
+       that all succeeds, ->readpage will be called again.
 
   sync_page: called by the VM to notify the backing store to perform all
        queued I/O operations for a page. I/O operations for other pages
        associated with this address_space object may also be performed.
 
+       This function is optional and is called only for pages with
+       PG_Writeback set while waiting for the writeback to complete.
+
   writepages: called by the VM to write out pages associated with the
-       address_space object.
+       address_space object.  If wbc->sync_mode is WBC_SYNC_ALL, then
+       the writeback_control will specify a range of pages that must be
+       written out.  If it is WBC_SYNC_NONE, then a nr_to_write is given
+       and that many pages should be written if possible.
+       If no ->writepages is given, then mpage_writepages is used
+       instead.  This will choose pages from the address space that are
+       tagged as DIRTY and will pass them to ->writepage.
 
   set_page_dirty: called by the VM to set a page dirty.
+        This is particularly needed if an address space attaches
+        private data to a page, and that data needs to be updated when
+        a page is dirtied.  This is called, for example, when a memory
+       mapped page gets modified.
+       If defined, it should set the PageDirty flag, and the
+        PAGECACHE_TAG_DIRTY tag in the radix tree.
 
   readpages: called by the VM to read pages associated with the address_space
-       object.
+       object. This is essentially just a vector version of
+       readpage.  Instead of just one page, several pages are
+       requested.
+       readpages is only used for read-ahead, so read errors are
+       ignored.  If anything goes wrong, feel free to give up.
 
   prepare_write: called by the generic write path in VM to set up a write
-       request for a page.
-
-  commit_write: called by the generic write path in VM to write page to
-       its backing store.
+       request for a page.  This indicates to the address space that
+       the given range of bytes is about to be written.  The
+       address_space should check that the write will be able to
+       complete, by allocating space if necessary and doing any other
+       internal housekeeping.  If the write will update parts of
+       any basic-blocks on storage, then those blocks should be
+       pre-read (if they haven't been read already) so that the
+       updated blocks can be written out properly.
+       The page will be locked.  If prepare_write wants to unlock the
+       page it, like readpage, may do so and return
+       AOP_TRUNCATED_PAGE.
+       In this case the prepare_write will be retried one the lock is
+       regained.
+
+  commit_write: If prepare_write succeeds, new data will be copied
+        into the page and then commit_write will be called.  It will
+        typically update the size of the file (if appropriate) and
+        mark the inode as dirty, and do any other related housekeeping
+        operations.  It should avoid returning an error if possible -
+        errors should have been handled by prepare_write.
 
   bmap: called by the VFS to map a logical block offset within object to
-       physical block number. This method is use by for the legacy FIBMAP
-       ioctl. Other uses are discouraged.
-
-  invalidatepage: called by the VM on truncate to disassociate a page from its
-       address_space mapping.
-
-  releasepage: called by the VFS to release filesystem specific metadata from
-       a page.
-
-  direct_IO: called by the VM for direct I/O writes and reads.
+       physical block number. This method is used by the FIBMAP
+       ioctl and for working with swap-files.  To be able to swap to
+       a file, the file must have a stable mapping to a block
+       device.  The swap system does not go through the filesystem
+       but instead uses bmap to find out where the blocks in the file
+       are and uses those addresses directly.
+
+
+  invalidatepage: If a page has PagePrivate set, then invalidatepage
+        will be called when part or all of the page is to be removed
+       from the address space.  This generally corresponds to either a
+       truncation or a complete invalidation of the address space
+       (in the latter case 'offset' will always be 0).
+       Any private data associated with the page should be updated
+       to reflect this truncation.  If offset is 0, then
+       the private data should be released, because the page
+       must be able to be completely discarded.  This may be done by
+        calling the ->releasepage function, but in this case the
+        release MUST succeed.
+
+  releasepage: releasepage is called on PagePrivate pages to indicate
+        that the page should be freed if possible.  ->releasepage
+        should remove any private data from the page and clear the
+        PagePrivate flag.  It may also remove the page from the
+        address_space.  If this fails for some reason, it may indicate
+        failure with a 0 return value.
+       This is used in two distinct though related cases.  The first
+        is when the VM finds a clean page with no active users and
+        wants to make it a free page.  If ->releasepage succeeds, the
+        page will be removed from the address_space and become free.
+
+       The second case if when a request has been made to invalidate
+        some or all pages in an address_space.  This can happen
+        through the fadvice(POSIX_FADV_DONTNEED) system call or by the
+        filesystem explicitly requesting it as nfs and 9fs do (when
+        they believe the cache may be out of date with storage) by
+        calling invalidate_inode_pages2().
+       If the filesystem makes such a call, and needs to be certain
+        that all pages are invalidated, then its releasepage will
+        need to ensure this.  Possibly it can clear the PageUptodate
+        bit if it cannot free private data yet.
+
+  direct_IO: called by the generic read/write routines to perform
+        direct_IO - that is IO requests which bypass the page cache
+        and transfer data directly between the storage and the
+        application's address space.
 
   get_xip_page: called by the VM to translate a block number to a page.
        The page is valid until the corresponding filesystem is unmounted.
        Filesystems that want to use execute-in-place (XIP) need to implement
        it.  An example implementation can be found in fs/ext2/xip.c.
 
+  migrate_page:  This is used to compact the physical memory usage.
+        If the VM wants to relocate a page (maybe off a memory card
+        that is signalling imminent failure) it will pass a new page
+       and an old page to this function.  migrate_page should
+       transfer any private data across and update any references
+        that it has to the page.
 
 The File Object
 ===============
index d3ad2c24490aa4361ad83d841aca57607f83e5db..ad3edaba4533cf33d5452e5b4bb877455000c05b 100644 (file)
@@ -23,7 +23,6 @@ char __init inkernel_firmware[] = "let's say that this is firmware\n";
 #endif
 
 static struct device ghost_device = {
-       .name      = "Ghost Device",
        .bus_id    = "ghost0",
 };
 
@@ -92,7 +91,7 @@ static void sample_probe_async(void)
 {
        /* Let's say that I can't sleep */
        int error;
-       error = request_firmware_nowait (THIS_MODULE,
+       error = request_firmware_nowait (THIS_MODULE, FW_ACTION_NOHOTPLUG,
                                         "sample_driver_fw", &ghost_device,
                                         "my device pointer",
                                         sample_probe_async_cont);
index 57b956aecbc52c0d4c7402611edc83304870dad0..9e1b0e4051cd0546985b9985fd308d301d537c41 100644 (file)
@@ -172,7 +172,6 @@ static void fw_remove_class_device(struct class_device *class_dev)
 static struct class_device *class_dev;
 
 static struct device my_device = {
-       .name      = "Sample Device",
        .bus_id    = "my_dev0",
 };
 
index 44a25f3f51d11cf5977c0542c1db71d4b501b75d..f8cb55c30b0fb4d3c8a9931d15c0eedb13684b46 100644 (file)
@@ -367,12 +367,17 @@ running once the system is up.
                tty<n>  Use the virtual console device <n>.
 
                ttyS<n>[,options]
+               ttyUSB0[,options]
                        Use the specified serial port.  The options are of
-                       the form "bbbbpn", where "bbbb" is the baud rate,
-                       "p" is parity ("n", "o", or "e"), and "n" is bits.
-                       Default is "9600n8".
-
-                       See also Documentation/serial-console.txt.
+                       the form "bbbbpnf", where "bbbb" is the baud rate,
+                       "p" is parity ("n", "o", or "e"), "n" is number of
+                       bits, and "f" is flow control ("r" for RTS or
+                       omit it).  Default is "9600n8".
+
+                       See Documentation/serial-console.txt for more
+                       information.  See
+                       Documentation/networking/netconsole.txt for an
+                       alternative.
 
                uart,io,<addr>[,options]
                uart,mmio,<addr>[,options]
index 5427f8c7df95c9ed18885b664bffb8406bbe05f8..145d27a5239547774fa1e67808ffa63e0277f19e 100644 (file)
@@ -25,7 +25,7 @@ the essid= string parameter is available via the kernel command line.
 This will change after the method of sorting out parameters for all
 the PCMCIA drivers is agreed upon.  If you must have a built in driver
 with nondefault parameters, they can be edited in
-/usr/src/linux/drivers/net/pcmcia/ray_cs.c.  Searching for MODULE_PARM
+/usr/src/linux/drivers/net/pcmcia/ray_cs.c.  Searching for module_param
 will find them all.
 
 Information on card services is available at:
index 6c689b0df2b81e9c5b1f914ca7a2c9068bdfea17..9a7bc8b3f479b2b82dbfa1056df060366dbafdec 100644 (file)
@@ -17,11 +17,13 @@ The format of this option is:
                        ttyX for any other virtual console
                        ttySx for a serial port
                        lp0 for the first parallel port
+                       ttyUSB0 for the first USB serial device
 
        options:        depend on the driver. For the serial port this
-                       defines the baudrate/parity/bits of the port,
-                       in the format BBBBPN, where BBBB is the speed,
-                       P is parity (n/o/e), and N is bits. Default is
+                       defines the baudrate/parity/bits/flow control of
+                       the port, in the format BBBBPNF, where BBBB is the
+                       speed, P is parity (n/o/e), N is number of bits,
+                       and F is flow control ('r' for RTS). Default is
                        9600n8. The maximum baudrate is 115200.
 
 You can specify multiple console= options on the kernel command line.
@@ -45,6 +47,9 @@ become the console.
 You will need to create a new device to use /dev/console. The official
 /dev/console is now character device 5,1.
 
+(You can also use a network device as a console.  See
+Documentation/networking/netconsole.txt for information on that.)
+
 Here's an example that will use /dev/ttyS1 (COM2) as the console.
 Replace the sample values as needed.
 
index 15d4fb975ac0b636f56f40a015e9ad06f583d102..f04ba6bb7395685719bb883abd74b7ee7c5333a0 100644 (file)
@@ -69,7 +69,7 @@ are available, for example IRQ, address, DMA.
 
 Warning, the options for different cards sometime use different names 
 for the same or a similar feature (dma1= versus dma16=).  As a last 
-resort, inspect the code (search for MODULE_PARM).
+resort, inspect the code (search for module_param).
 
 Notes:
 
index 88d6cf8b39f309150ed7926acf3cc2e6d2c65b33..b5443270986307e7b5275849540d014e02c173c9 100644 (file)
@@ -88,7 +88,7 @@ parameters.  for a copy email: twoller@crystal.cirrus.com
 
 MODULE_PARMS definitions
 ------------------------
-MODULE_PARM(defaultorder, "i");
+module_param(defaultorder, ulong, 0);
 defaultorder=N
 where N is a value from 1 to 12
 The buffer order determines the size of the dma buffer for the driver.
@@ -98,18 +98,18 @@ to not underrun the dma buffer as easily.  As default, use 32k (order=3)
 rather than 64k as some of the games work more responsively.
 (2^N) * PAGE_SIZE = allocated buffer size
 
-MODULE_PARM(cs_debuglevel, "i");
-MODULE_PARM(cs_debugmask, "i");
+module_param(cs_debuglevel, ulong, 0644);
+module_param(cs_debugmask, ulong, 0644);
 cs_debuglevel=N
 cs_debugmask=0xMMMMMMMM
 where N is a value from 0 (no debug printfs), to 9 (maximum)
 0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source).
 
-MODULE_PARM(hercules_egpio_disable, "i");
+module_param(hercules_egpio_disable, ulong, 0);
 hercules_egpio_disable=N
 where N is a 0 (enable egpio), or a 1 (disable egpio support)
 
-MODULE_PARM(initdelay, "i");
+module_param(initdelay, ulong, 0);
 initdelay=N
 This value is used to determine the millescond delay during the initialization
 code prior to powering up the PLL.  On laptops this value can be used to
@@ -118,19 +118,19 @@ system is booted under battery power then the mdelay()/udelay() functions fail t
 properly delay the required time.  Also, if the system is booted under AC power
 and then the power removed, the mdelay()/udelay() functions will not delay properly.
  
-MODULE_PARM(powerdown, "i");
+module_param(powerdown, ulong, 0);
 powerdown=N
 where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown)
 
 
-MODULE_PARM(external_amp, "i");
+module_param(external_amp, bool, 0);
 external_amp=1
 if N is set to 1, then force enabling the EAPD support in the primary AC97 codec.
 override the detection logic and force the external amp bit in the AC97 0x26 register
 to be reset (0).  EAPD should be 0 for powerup, and 1 for powerdown.  The VTB Santa Cruz
 card has inverted logic, so there is a special function for these cards.
 
-MODULE_PARM(thinkpad, "i");
+module_param(thinkpad, bool, 0);
 thinkpad=1
 if N is set to 1, then force enabling the clkrun functionality.
 Currently, when the part is being used, then clkrun is disabled for the entire system,
index e415e36045395bd0fdc66cbcc9bffd1b2d8424a5..464e4cec94cb82eca91d20d0e411bfdf61c32792 100644 (file)
@@ -1,7 +1,7 @@
 c-qcam - Connectix Color QuickCam video4linux kernel driver
 
 Copyright (C) 1999  Dave Forrest  <drf5n@virginia.edu>
-                    released under GNU GPL.
+                   released under GNU GPL.
 
 1999-12-08 Dave Forrest, written with kernel version 2.2.12 in mind
 
@@ -45,21 +45,21 @@ configuration.  The appropriate flags are:
     CONFIG_PNP_PARPORT   M for autoprobe.o IEEE1284 readback module
     CONFIG_PRINTER_READBACK M for parport_probe.o IEEE1284 readback module
     CONFIG_VIDEO_DEV     M    for videodev.o video4linux module
-    CONFIG_VIDEO_CQCAM   M    for c-qcam.o  Color Quickcam module 
+    CONFIG_VIDEO_CQCAM   M    for c-qcam.o  Color Quickcam module
 
   With these flags, the kernel should compile and install the modules.
 To record and monitor the compilation, I use:
 
  (make zlilo ; \
   make modules; \
-  make modules_install ; 
+  make modules_install ;
   depmod -a ) &>log &
  less log  # then a capital 'F' to watch the progress
-  
+
 But that is my personal preference.
 
 2.2 Configuration
+
   The configuration requires module configuration and device
 configuration.  I like kmod or kerneld process with the
 /etc/modprobe.conf file so the modules can automatically load/unload as
@@ -68,7 +68,7 @@ using MAKEDEV, or need to be created.  The following sections detail
 these procedures.
 
 
-2.1 Module Configuration  
+2.1 Module Configuration
 
   Using modules requires a bit of work to install and pass the
 parameters.  Understand that entries in /etc/modprobe.conf of:
@@ -128,9 +128,9 @@ system (CONFIG_PROC_FS), the parallel printer support
 (CONFIG_PRINTER), the IEEE 1284 system,(CONFIG_PRINTER_READBACK), you
 should be able to read some identification from your quickcam with
 
-         modprobe -v parport
-         modprobe -v parport_probe
-         cat /proc/parport/PORTNUMBER/autoprobe
+        modprobe -v parport
+        modprobe -v parport_probe
+        cat /proc/parport/PORTNUMBER/autoprobe
 Returns:
   CLASS:MEDIA;
   MODEL:Color QuickCam 2.0;
@@ -140,7 +140,7 @@ Returns:
 and well.  A common problem is that the current driver does not
 reliably detect a c-qcam, even though one is attached.  In this case,
 
-     modprobe -v c-qcam     
+     modprobe -v c-qcam
 or
      insmod -v c-qcam
 
@@ -152,16 +152,16 @@ video4linux mailing list and archive for more current information.
 3.1 Checklist:
 
   Can you get an image?
-            v4lgrab >qcam.ppm ; wc qcam.ppm ; xv qcam.ppm
+           v4lgrab >qcam.ppm ; wc qcam.ppm ; xv qcam.ppm
 
-  Is a working c-qcam connected to the port? 
-            grep ^ /proc/parport/?/autoprobe
+  Is a working c-qcam connected to the port?
+           grep ^ /proc/parport/?/autoprobe
 
-  Do the /dev/video* files exist?  
-            ls -lad /dev/video
+  Do the /dev/video* files exist?
+           ls -lad /dev/video
 
-  Is the c-qcam module loaded?     
-            modprobe -v c-qcam ; lsmod
+  Is the c-qcam module loaded?
+           modprobe -v c-qcam ; lsmod
 
   Does the camera work with alternate programs? cqcam, etc?
 
@@ -174,7 +174,7 @@ video4linux mailing list and archive for more current information.
 isn't, you might try patching the c-qcam module to add a parport=xxx
 option as in the bw-qcam module so you can specify the parallel port:
 
-       insmod -v c-qcam parport=0  
+       insmod -v c-qcam parport=0
 
 And bypass the detection code, see ../../drivers/char/c-qcam.c and
 look for the 'qc_detect' code and call.
@@ -183,12 +183,12 @@ look for the 'qc_detect' code and call.
 this work is documented at the video4linux2 site listed below.
 
 
-9.0 --- A sample program using v4lgrabber, 
+9.0 --- A sample program using v4lgrabber,
 
 This program is a simple image grabber that will copy a frame from the
 first video device, /dev/video0 to standard output in portable pixmap
 format (.ppm)  Using this like: 'v4lgrab | convert - c-qcam.jpg'
-produced this picture of me at 
+produced this picture of me at
     http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
 
 -------------------- 8< ---------------- 8< -----------------------------
@@ -202,8 +202,8 @@ produced this picture of me at
  *      Use as:
  *              v4lgrab >image.ppm
  *
- *     Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>  
- *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c 
+ *     Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
+ *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
  *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
  *
  */
@@ -225,55 +225,55 @@ produced this picture of me at
 
 #define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
 {                                                                       \
-        switch (format)                                                 \
-        {                                                               \
-                case VIDEO_PALETTE_GREY:                                \
-                        switch (depth)                                  \
-                        {                                               \
-                                case 4:                                 \
-                                case 6:                                 \
-                                case 8:                                 \
-                                        (r) = (g) = (b) = (*buf++ << 8);\
-                                        break;                          \
-                                                                        \
-                                case 16:                                \
-                                        (r) = (g) = (b) =               \
-                                                *((unsigned short *) buf);      \
-                                        buf += 2;                       \
-                                        break;                          \
-                        }                                               \
-                        break;                                          \
-                                                                        \
-                                                                        \
-                case VIDEO_PALETTE_RGB565:                              \
-                {                                                       \
-                        unsigned short tmp = *(unsigned short *)buf;    \
-                        (r) = tmp&0xF800;                               \
-                        (g) = (tmp<<5)&0xFC00;                          \
-                        (b) = (tmp<<11)&0xF800;                         \
-                        buf += 2;                                       \
-                }                                                       \
-                break;                                                  \
-                                                                        \
-                case VIDEO_PALETTE_RGB555:                              \
-                        (r) = (buf[0]&0xF8)<<8;                         \
-                        (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
-                        (b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
-                        buf += 2;                                       \
-                        break;                                          \
-                                                                        \
-                case VIDEO_PALETTE_RGB24:                               \
-                        (r) = buf[0] << 8; (g) = buf[1] << 8;           \
-                        (b) = buf[2] << 8;                              \
-                        buf += 3;                                       \
-                        break;                                          \
-                                                                        \
-                default:                                                \
-                        fprintf(stderr,                                 \
-                                "Format %d not yet supported\n",        \
-                                format);                                \
-        }                                                               \
-}                                               
+       switch (format)                                                 \
+       {                                                               \
+               case VIDEO_PALETTE_GREY:                                \
+                       switch (depth)                                  \
+                       {                                               \
+                               case 4:                                 \
+                               case 6:                                 \
+                               case 8:                                 \
+                                       (r) = (g) = (b) = (*buf++ << 8);\
+                                       break;                          \
+                                                                       \
+                               case 16:                                \
+                                       (r) = (g) = (b) =               \
+                                               *((unsigned short *) buf);      \
+                                       buf += 2;                       \
+                                       break;                          \
+                       }                                               \
+                       break;                                          \
+                                                                       \
+                                                                       \
+               case VIDEO_PALETTE_RGB565:                              \
+               {                                                       \
+                       unsigned short tmp = *(unsigned short *)buf;    \
+                       (r) = tmp&0xF800;                               \
+                       (g) = (tmp<<5)&0xFC00;                          \
+                       (b) = (tmp<<11)&0xF800;                         \
+                       buf += 2;                                       \
+               }                                                       \
+               break;                                                  \
+                                                                       \
+               case VIDEO_PALETTE_RGB555:                              \
+                       (r) = (buf[0]&0xF8)<<8;                         \
+                       (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
+                       (b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
+                       buf += 2;                                       \
+                       break;                                          \
+                                                                       \
+               case VIDEO_PALETTE_RGB24:                               \
+                       (r) = buf[0] << 8; (g) = buf[1] << 8;           \
+                       (b) = buf[2] << 8;                              \
+                       buf += 3;                                       \
+                       break;                                          \
+                                                                       \
+               default:                                                \
+                       fprintf(stderr,                                 \
+                               "Format %d not yet supported\n",        \
+                               format);                                \
+       }                                                               \
+}
 
 int get_brightness_adj(unsigned char *image, long size, int *brightness) {
   long i, tot = 0;
@@ -324,40 +324,40 @@ int main(int argc, char ** argv)
     if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
       vpic.depth=6;
       if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-        vpic.depth=4;
-        if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-          fprintf(stderr, "Unable to find a supported capture format.\n");
-          close(fd);
-          exit(1);
-        }
+       vpic.depth=4;
+       if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+         fprintf(stderr, "Unable to find a supported capture format.\n");
+         close(fd);
+         exit(1);
+       }
       }
     }
   } else {
     vpic.depth=24;
     vpic.palette=VIDEO_PALETTE_RGB24;
-    
+
     if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
       vpic.palette=VIDEO_PALETTE_RGB565;
       vpic.depth=16;
-      
+
       if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-        vpic.palette=VIDEO_PALETTE_RGB555;
-        vpic.depth=15;
-        
-        if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-          fprintf(stderr, "Unable to find a supported capture format.\n");
-          return -1;
-        }
+       vpic.palette=VIDEO_PALETTE_RGB555;
+       vpic.depth=15;
+
+       if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+         fprintf(stderr, "Unable to find a supported capture format.\n");
+         return -1;
+       }
       }
     }
   }
-  
+
   buffer = malloc(win.width * win.height * bpp);
   if (!buffer) {
     fprintf(stderr, "Out of memory.\n");
     exit(1);
   }
-  
+
   do {
     int newbright;
     read(fd, buffer, win.width * win.height * bpp);
@@ -365,8 +365,8 @@ int main(int argc, char ** argv)
     if (f) {
       vpic.brightness += (newbright << 8);
       if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-        perror("VIDIOSPICT");
-        break;
+       perror("VIDIOSPICT");
+       break;
       }
     }
   } while (f);
@@ -381,7 +381,7 @@ int main(int argc, char ** argv)
     fputc(g>>8, stdout);
     fputc(b>>8, stdout);
   }
-    
+
   close(fd);
   return 0;
 }
index c95e7bbc0fdfc8763aaaffa01194b2f235891c35..19cd3bf24981aa254b63b960f68a3eefb5bb1ba0 100644 (file)
@@ -87,7 +87,7 @@ hardware configuration of the parport. You can give the boot-parameter
 at the LILO-prompt or specify it in lilo.conf. I use the following
 append-line in lilo.conf:
 
-        append="parport=0x378,7,3"
+       append="parport=0x378,7,3"
 
 See Documentation/parport.txt for more information about the
 configuration of the parport and the values given above. Do not simply
@@ -175,7 +175,7 @@ THANKS (in no particular order):
 - Manuel J. Petit de Gabriel <mpetit@dit.upm.es> for providing help
   with Isabel (http://isabel.dit.upm.es/)
 - Bas Huisman <bhuism@cs.utwente.nl> for writing the initial parport code
-- Jarl Totland <Jarl.Totland@bdc.no> for setting up the mailing list 
+- Jarl Totland <Jarl.Totland@bdc.no> for setting up the mailing list
   and maintaining the web-server[3]
 - Chris Whiteford <Chris@informinteractive.com> for fixes related to the
   1.02 firmware
index 52c94bd7dca1f909cc16ddc2f40351cfbefad5ab..be9f21b8455589b6c697b888c1132858bce043ce 100644 (file)
@@ -28,7 +28,7 @@ Iomega Buz:
 * Philips saa7111 TV decoder
 * Philips saa7185 TV encoder
 Drivers to use: videodev, i2c-core, i2c-algo-bit,
-                videocodec, saa7111, saa7185, zr36060, zr36067
+               videocodec, saa7111, saa7185, zr36060, zr36067
 Inputs/outputs: Composite and S-video
 Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
 Card number: 7
@@ -39,7 +39,7 @@ Linux Media Labs LML33:
 * Brooktree bt819 TV decoder
 * Brooktree bt856 TV encoder
 Drivers to use: videodev, i2c-core, i2c-algo-bit,
-                videocodec, bt819, bt856, zr36060, zr36067
+               videocodec, bt819, bt856, zr36060, zr36067
 Inputs/outputs: Composite and S-video
 Norms: PAL (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
 Card number: 5
@@ -50,7 +50,7 @@ Linux Media Labs LML33R10:
 * Philips saa7114 TV decoder
 * Analog Devices adv7170 TV encoder
 Drivers to use: videodev, i2c-core, i2c-algo-bit,
-                videocodec, saa7114, adv7170, zr36060, zr36067
+               videocodec, saa7114, adv7170, zr36060, zr36067
 Inputs/outputs: Composite and S-video
 Norms: PAL (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
 Card number: 6
@@ -61,7 +61,7 @@ Pinnacle/Miro DC10(new):
 * Philips saa7110a TV decoder
 * Analog Devices adv7176 TV encoder
 Drivers to use: videodev, i2c-core, i2c-algo-bit,
-                videocodec, saa7110, adv7175, zr36060, zr36067
+               videocodec, saa7110, adv7175, zr36060, zr36067
 Inputs/outputs: Composite, S-video and Internal
 Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
 Card number: 1
@@ -84,7 +84,7 @@ Pinnacle/Miro DC10(old): *
 * Micronas vpx3220a TV decoder
 * mse3000 TV encoder or Analog Devices adv7176 TV encoder *
 Drivers to use: videodev, i2c-core, i2c-algo-bit,
-                videocodec, vpx3220, mse3000/adv7175, zr36050, zr36016, zr36067
+               videocodec, vpx3220, mse3000/adv7175, zr36050, zr36016, zr36067
 Inputs/outputs: Composite, S-video and Internal
 Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
 Card number: 0
@@ -96,7 +96,7 @@ Pinnacle/Miro DC30: *
 * Micronas vpx3225d/vpx3220a/vpx3216b TV decoder
 * Analog Devices adv7176 TV encoder
 Drivers to use: videodev, i2c-core, i2c-algo-bit,
-                videocodec, vpx3220/vpx3224, adv7175, zr36050, zr36016, zr36067
+               videocodec, vpx3220/vpx3224, adv7175, zr36050, zr36016, zr36067
 Inputs/outputs: Composite, S-video and Internal
 Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps)
 Card number: 3
@@ -123,11 +123,11 @@ Note: use encoder=X or decoder=X for non-default i2c chips (see i2c-id.h)
 
 The best know TV standards are NTSC/PAL/SECAM. but for decoding a frame that
 information is not enough. There are several formats of the TV standards.
-And not every TV decoder is able to handle every format. Also the every 
-combination is supported by the driver. There are currently 11 different 
-tv broadcast formats all aver the world. 
+And not every TV decoder is able to handle every format. Also the every
+combination is supported by the driver. There are currently 11 different
+tv broadcast formats all aver the world.
 
-The CCIR defines parameters needed for broadcasting the signal. 
+The CCIR defines parameters needed for broadcasting the signal.
 The CCIR has defined different standards: A,B,D,E,F,G,D,H,I,K,K1,L,M,N,...
 The CCIR says not much about about the colorsystem used !!!
 And talking about a colorsystem says not to much about how it is broadcast.
@@ -136,18 +136,18 @@ The CCIR standards A,E,F are not used any more.
 
 When you speak about NTSC, you usually mean the standard: CCIR - M using
 the NTSC colorsystem which is used in the USA, Japan, Mexico, Canada
-and a few others. 
+and a few others.
 
 When you talk about PAL, you usually mean: CCIR - B/G using the PAL
-colorsystem which is used in many Countries. 
+colorsystem which is used in many Countries.
 
-When you talk about SECAM, you mean: CCIR - L using the SECAM Colorsystem 
+When you talk about SECAM, you mean: CCIR - L using the SECAM Colorsystem
 which is used in France, and a few others.
 
 There the other version of SECAM, CCIR - D/K is used in Bulgaria, China,
-Slovakai, Hungary, Korea (Rep.), Poland, Rumania and a others. 
+Slovakai, Hungary, Korea (Rep.), Poland, Rumania and a others.
 
-The CCIR - H uses the PAL colorsystem (sometimes SECAM) and is used in 
+The CCIR - H uses the PAL colorsystem (sometimes SECAM) and is used in
 Egypt, Libya, Sri Lanka, Syrain Arab. Rep.
 
 The CCIR - I uses the PAL colorsystem, and is used in Great Britain, Hong Kong,
@@ -158,30 +158,30 @@ and is used in Argentinia, Uruguay, an a few others
 
 We do not talk about how the audio is broadcast !
 
-A rather good sites about the TV standards are: 
+A rather good sites about the TV standards are:
 http://www.sony.jp/ServiceArea/Voltage_map/
 http://info.electronicwerkstatt.de/bereiche/fernsehtechnik/frequenzen_und_normen/Fernsehnormen/
 and http://www.cabl.com/restaurant/channel.html
 
 Other weird things around: NTSC 4.43 is a modificated NTSC, which is mainly
 used in PAL VCR's that are able to play back NTSC. PAL 60 seems to be the same
-as NTSC 4.43 . The Datasheets also talk about NTSC 44, It seems as if it would 
-be the same as NTSC 4.43. 
+as NTSC 4.43 . The Datasheets also talk about NTSC 44, It seems as if it would
+be the same as NTSC 4.43.
 NTSC Combs seems to be a decoder mode where the decoder uses a comb filter
 to split coma and luma instead of a Delay line.
 
 But I did not defiantly find out what NTSC Comb is.
 
 Philips saa7111 TV decoder
-was introduced in 1997, is used in the BUZ and 
-can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC N, NTSC 4.43 and SECAM 
+was introduced in 1997, is used in the BUZ and
+can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC N, NTSC 4.43 and SECAM
 
 Philips saa7110a TV decoder
 was introduced in 1995, is used in the Pinnacle/Miro DC10(new), DC10+ and
-can handle: PAL B/G, NTSC M and SECAM 
+can handle: PAL B/G, NTSC M and SECAM
 
 Philips saa7114 TV decoder
-was introduced in 2000, is used in the LML33R10 and  
+was introduced in 2000, is used in the LML33R10 and
 can handle: PAL B/G/D/H/I/N, PAL N, PAL M, NTSC M, NTSC 4.43 and SECAM
 
 Brooktree bt819 TV decoder
@@ -206,7 +206,7 @@ was introduced in 1996, is used in the BUZ
 can generate: PAL B/G, NTSC M
 
 Brooktree bt856 TV Encoder
-was introduced in 1994, is used in the LML33 
+was introduced in 1994, is used in the LML33
 can generate: PAL B/D/G/H/I/N, PAL M, NTSC M, PAL-N (Argentina)
 
 Analog Devices adv7170 TV Encoder
@@ -221,9 +221,9 @@ ITT mse3000 TV encoder
 was introduced in 1991, is used in the DC10 old
 can generate: PAL , NTSC , SECAM
 
-The adv717x, should be able to produce PAL N. But you find nothing PAL N 
+The adv717x, should be able to produce PAL N. But you find nothing PAL N
 specific in the registers. Seem that you have to reuse a other standard
-to generate PAL N, maybe it would work if you use the PAL M settings. 
+to generate PAL N, maybe it would work if you use the PAL M settings.
 
 ==========================
 
@@ -261,7 +261,7 @@ Here's my experience of using LML33 and Buz on various motherboards:
 
 VIA MVP3
        Forget it. Pointless. Doesn't work.
-Intel 430FX (Pentium 200) 
+Intel 430FX (Pentium 200)
        LML33 perfect, Buz tolerable (3 or 4 frames dropped per movie)
 Intel 440BX (early stepping)
        LML33 tolerable. Buz starting to get annoying (6-10 frames/hour)
@@ -438,52 +438,52 @@ importance of buffer sizes:
 > -q 25 -b 128 : 24.655.992
 > -q 25 -b 256 : 25.859.820
 
-I woke up, and can't go to sleep again. I'll kill some time explaining why 
+I woke up, and can't go to sleep again. I'll kill some time explaining why
 this doesn't look strange to me.
 
-Let's do some math using a width of 704 pixels. I'm not sure whether the Buz 
+Let's do some math using a width of 704 pixels. I'm not sure whether the Buz
 actually use that number or not, but that's not too important right now.
 
-704x288 pixels, one field, is 202752 pixels. Divided by 64 pixels per block; 
-3168 blocks per field. Each pixel consist of two bytes; 128 bytes per block; 
-1024 bits per block. 100% in the new driver mean 1:2 compression; the maximum 
-output becomes 512 bits per block. Actually 510, but 512 is simpler to use 
+704x288 pixels, one field, is 202752 pixels. Divided by 64 pixels per block;
+3168 blocks per field. Each pixel consist of two bytes; 128 bytes per block;
+1024 bits per block. 100% in the new driver mean 1:2 compression; the maximum
+output becomes 512 bits per block. Actually 510, but 512 is simpler to use
 for calculations.
 
-Let's say that we specify d1q50. We thus want 256 bits per block; times 3168 
-becomes 811008 bits; 101376 bytes per field. We're talking raw bits and bytes 
-here, so we don't need to do any fancy corrections for bits-per-pixel or such 
+Let's say that we specify d1q50. We thus want 256 bits per block; times 3168
+becomes 811008 bits; 101376 bytes per field. We're talking raw bits and bytes
+here, so we don't need to do any fancy corrections for bits-per-pixel or such
 things. 101376 bytes per field.
 
-d1 video contains two fields per frame. Those sum up to 202752 bytes per 
+d1 video contains two fields per frame. Those sum up to 202752 bytes per
 frame, and one of those frames goes into each buffer.
 
-But wait a second! -b128 gives 128kB buffers! It's not possible to cram 
+But wait a second! -b128 gives 128kB buffers! It's not possible to cram
 202752 bytes of JPEG data into 128kB!
 
-This is what the driver notice and automatically compensate for in your 
+This is what the driver notice and automatically compensate for in your
 examples. Let's do some math using this information:
 
-128kB is 131072 bytes. In this buffer, we want to store two fields, which 
-leaves 65536 bytes for each field. Using 3168 blocks per field, we get 
-20.68686868... available bytes per block; 165 bits. We can't allow the 
-request for 256 bits per block when there's only 165 bits available! The -q50 
-option is silently overridden, and the -b128 option takes precedence, leaving 
+128kB is 131072 bytes. In this buffer, we want to store two fields, which
+leaves 65536 bytes for each field. Using 3168 blocks per field, we get
+20.68686868... available bytes per block; 165 bits. We can't allow the
+request for 256 bits per block when there's only 165 bits available! The -q50
+option is silently overridden, and the -b128 option takes precedence, leaving
 us with the equivalence of -q32.
 
-This gives us a data rate of 165 bits per block, which, times 3168, sums up 
-to 65340 bytes per field, out of the allowed 65536. The current driver has 
-another level of rate limiting; it won't accept -q values that fill more than 
-6/8 of the specified buffers. (I'm not sure why. "Playing it safe" seem to be 
-a safe bet. Personally, I think I would have lowered requested-bits-per-block 
-by one, or something like that.) We can't use 165 bits per block, but have to 
-lower it again, to 6/8 of the available buffer space: We end up with 124 bits 
-per block, the equivalence of -q24. With 128kB buffers, you can't use greater 
+This gives us a data rate of 165 bits per block, which, times 3168, sums up
+to 65340 bytes per field, out of the allowed 65536. The current driver has
+another level of rate limiting; it won't accept -q values that fill more than
+6/8 of the specified buffers. (I'm not sure why. "Playing it safe" seem to be
+a safe bet. Personally, I think I would have lowered requested-bits-per-block
+by one, or something like that.) We can't use 165 bits per block, but have to
+lower it again, to 6/8 of the available buffer space: We end up with 124 bits
+per block, the equivalence of -q24. With 128kB buffers, you can't use greater
 than -q24 at -d1. (And PAL, and 704 pixels width...)
 
-The third example is limited to -q24 through the same process. The second 
-example, using very similar calculations, is limited to -q48. The only 
-example that actually grab at the specified -q value is the last one, which 
+The third example is limited to -q24 through the same process. The second
+example, using very similar calculations, is limited to -q48. The only
+example that actually grab at the specified -q value is the last one, which
 is clearly visible, looking at the file size.
 --
 
index 6b749133696756d37eb9f88879c4d6945ca4c6a6..611315f87c3ec2fd818529093fbd14772fb71030 100644 (file)
@@ -14,13 +14,13 @@ Hauppauge Win/TV pci (version 405):
 
 Microchip 24LC02B or
 Philips 8582E2Y: 256 Byte EEPROM with configuration information
-                 I2C 0xa0-0xa1, (24LC02B also responds to 0xa2-0xaf)
+                I2C 0xa0-0xa1, (24LC02B also responds to 0xa2-0xaf)
 Philips SAA5246AGP/E: Videotext decoder chip, I2C 0x22-0x23
 TDA9800: sound decoder
 Winbond W24257AS-35: 32Kx8 CMOS static RAM (Videotext buffer mem)
 14052B: analog switch for selection of sound source
 
-PAL: 
+PAL:
 TDA5737: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners
 TSA5522: 1.4 GHz I2C-bus controlled synthesizer, I2C 0xc2-0xc3
 
index 8e31e9e36bf7ee2f123d7125959f1980e1df1c03..2b8b0079f7c788a2888821d65b691779b8c5b15d 100644 (file)
@@ -3,7 +3,7 @@
 - Start capturing by pressing "c" or by selecting it via a menu!!!
 
 - The memory of some S3 cards is not recognized right:
-  
+
   First of all, if you are not using XFree-3.2 or newer, upgrade AT LEAST to
   XFree-3.2A! This solved the problem for most people.
 
   (mostly with Trio 64 but also with some others)
   Get the free demo version of Accelerated X from www.xinside.com and try
   bttv with it. bttv seems to work with most S3 cards with Accelerated X.
-  
+
   Since I do not know much (better make that almost nothing) about VGA card
   programming I do not know the reason for this.
   Looks like XFree does something different when setting up the video memory?
-  Maybe somebody can enlighten me?  
-  Would be nice if somebody could get this to work with XFree since 
-  Accelerated X costs more than some of the grabber cards ... 
+  Maybe somebody can enlighten me?
+  Would be nice if somebody could get this to work with XFree since
+  Accelerated X costs more than some of the grabber cards ...
+
   Better linear frame buffer support for S3 cards will probably be in
   XFree 4.0.
-  
+
 - Grabbing is not switched off when changing consoles with XFree.
   That's because XFree and some AcceleratedX versions do not send unmap
   events.
 
 - Some popup windows (e.g. of the window manager) are not refreshed.
-  
+
   Disable backing store by starting X with the option "-bs"
 
 - When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
index e8edb87df711846bc24ae75db728490d414da7ab..92e03929a6b2c1ac2b77cc146e1d2b5eed9fc8a9 100644 (file)
@@ -38,9 +38,9 @@ tolerate.
 ------------------------
 
 When using the 430FX PCI, the following rules will ensure
-compatibility: 
+compatibility:
 
- (1) Deassert REQ at the same time as asserting FRAME. 
+ (1) Deassert REQ at the same time as asserting FRAME.
  (2) Do not reassert REQ to request another bus transaction until after
      finish-ing the previous transaction.
 
index 2085399da7d4c3274b39c133bd253523af370ef1..950aa781c2e98722d11b1d51e9cf22026d257bbe 100644 (file)
@@ -1,6 +1,6 @@
 Many thanks to:
 
-- Markus Schroeder <schroedm@uni-duesseldorf.de> for information on the Bt848 
+- Markus Schroeder <schroedm@uni-duesseldorf.de> for information on the Bt848
   and tuner programming and his control program xtvc.
 
 - Martin Buck <martin-2.buck@student.uni-ulm.de> for his great Videotext
@@ -16,7 +16,7 @@ Many thanks to:
 - MIRO for providing a free PCTV card and detailed information about the
   components on their cards. (E.g. how the tuner type is detected)
   Without their card I could not have debugged the NTSC mode.
-       
+
 - Hauppauge for telling how the sound input is selected and what components
   they do and will use on their radio cards.
   Also many thanks for faxing me the FM1216 data sheet.
index 2b75345f13e3a428a862b18348e5a724a7b4c3fc..d1f3ed199186e1b059d3b31e66284d680513a846 100644 (file)
@@ -131,17 +131,17 @@ Check Stereo:   BASE <-- 0xd8  (current volume, stereo detect,
                x=0xff ==> "not stereo", x=0xfd ==> "stereo detected"
 
 Set Frequency:  code = (freq*40) + 10486188
-                foreach of the 24 bits in code,
-                (from Least to Most Significant):
-                  to write a "zero" bit,
-                    BASE <-- 0x01  (audio mute, no stereo detect, radio
+               foreach of the 24 bits in code,
+               (from Least to Most Significant):
+                 to write a "zero" bit,
+                   BASE <-- 0x01  (audio mute, no stereo detect, radio
                                    disable, "zero" bit phase 1, tuner adjust)
-                    BASE <-- 0x03  (audio mute, no stereo detect, radio
+                   BASE <-- 0x03  (audio mute, no stereo detect, radio
                                    disable, "zero" bit phase 2, tuner adjust)
-                  to write a "one" bit,
-                    BASE <-- 0x05  (audio mute, no stereo detect, radio
+                 to write a "one" bit,
+                   BASE <-- 0x05  (audio mute, no stereo detect, radio
                                    disable, "one" bit phase 1, tuner adjust)
-                    BASE <-- 0x07  (audio mute, no stereo detect, radio
+                   BASE <-- 0x07  (audio mute, no stereo detect, radio
                                    disable, "one" bit phase 2, tuner adjust)
 
 ----------------------------------------------------------------------------
index e7ac33a7eb06c5fa5b63f9cef1e2adcdb6e5b57a..78a651254b84eaa57bf0a8b662e3478190b9c0d7 100644 (file)
@@ -26,7 +26,7 @@ is called VIDEO_PALETTE_YUV422 (16 bpp).
 A minimal test application (with source) is available from:
   http://hem.fyristorg.com/mogul/w9966.html
 
-The slow framerate is due to missing DMA ECP read support in the 
+The slow framerate is due to missing DMA ECP read support in the
 parport drivers. I might add working EPP support later.
 
 Good luck!
index 5d6357eefde4ce15f3d2dd0a23c231da9a9a4361..ac6d92d0194470170aa3c569b3de1179557efdb7 100644 (file)
@@ -2,7 +2,7 @@ Driver for Trust Computer Products Framegrabber, version 0.6.1
 ------ --- ----- -------- -------- ------------  ------- - - -
 
 - ZORAN ------------------------------------------------------
- Author: Pauline Middelink <middelin@polyware.nl> 
+ Author: Pauline Middelink <middelin@polyware.nl>
    Date: 18 September 1999
 Version: 0.6.1
 
@@ -115,7 +115,7 @@ After making/checking the devices do:
 <n> is the cardtype of the card you have. The cardnumber can
 be found in the source of zr36120. Look for tvcards. If your
 card is not there, please try if any other card gives some
-response, and mail me if you got a working tvcard addition. 
+response, and mail me if you got a working tvcard addition.
 
 PS. <TVCard editors behold!)
     Dont forget to set video_input to the number of inputs
index f854f310e81fc4102c86dbcda6bb2878b7d43cdc..4e8fbbc5566de6683aa151d167a64a4e13eb0ed0 100644 (file)
@@ -147,6 +147,18 @@ M: p_gortmaker@yahoo.com
 L:     netdev@vger.kernel.org
 S:     Maintained
 
+9P FILE SYSTEM
+P:      Eric Van Hensbergen
+M:      ericvh@gmail.com
+P:      Ron Minnich
+M:      rminnich@lanl.gov
+P:      Latchesar Ionkov
+M:      lucho@ionkov.net
+L:      v9fs-developer@lists.sourceforge.net
+W:      http://v9fs.sf.net
+T:      git kernel.org:/pub/scm/linux/kernel/ericvh/v9fs.git
+S:      Maintained
+
 A2232 SERIAL BOARD DRIVER
 P:     Enver Haase
 M:     ehaase@inf.fu-berlin.de
@@ -2212,13 +2224,6 @@ S:       Maintained
 RISCOM8 DRIVER
 S:     Orphan
 
-RTLINUX  REALTIME  LINUX
-P:     Victor Yodaiken
-M:     yodaiken@fsmlabs.com
-L:     rtl@rtlinux.org
-W:     www.rtlinux.org
-S:     Maintained
-
 S3 SAVAGE FRAMEBUFFER DRIVER
 P:      Antonino Daplas
 M:      adaplas@pol.net
@@ -2531,7 +2536,6 @@ S:        Unsupported ?
 STRADIS MPEG-2 DECODER DRIVER
 P:     Nathan Laredo
 M:     laredo@gnu.org
-W:     http://mpeg.openprojects.net/
 W:     http://www.stradis.com/
 S:     Maintained
 
@@ -2650,7 +2654,7 @@ S:        Maintained
 
 TUN/TAP driver
 P:     Maxim Krasnyansky
-M:     maxk@qualcomm.com, max_mk@yahoo.com
+M:     maxk@qualcomm.com
 L:     vtun@office.satix.net
 W:     http://vtun.sourceforge.net/tun
 S:     Maintained
@@ -2979,18 +2983,6 @@ L:       rio500-users@lists.sourceforge.net
 W:     http://rio500.sourceforge.net
 S:     Maintained
 
-V9FS FILE SYSTEM
-P:      Eric Van Hensbergen
-M:      ericvh@gmail.com
-P:      Ron Minnich
-M:      rminnich@lanl.gov
-P:      Latchesar Ionkov
-M:      lucho@ionkov.net
-L:      v9fs-developer@lists.sourceforge.net
-W:      http://v9fs.sf.net
-T:      git kernel.org:/pub/scm/linux/kernel/ericvh/v9fs-devel.git
-S:      Maintained
-
 VIDEO FOR LINUX
 P:     Mauro Carvalho Chehab
 M:     mchehab@infradead.org
index 6888816a1935f3047f96f09980ebfe58447adefa..10245408247446818755c7256cdcc9fe54531533 100644 (file)
@@ -40,6 +40,7 @@
 #include <asm/hardware/scoop.h>
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/locomo.h>
+#include <asm/arch/mcp.h>
 
 #include "generic.h"
 
@@ -66,6 +67,32 @@ struct platform_device colliescoop_device = {
        .resource       = collie_scoop_resources,
 };
 
+static struct scoop_pcmcia_dev collie_pcmcia_scoop[] = {
+{
+       .dev        = &colliescoop_device.dev,
+       .irq        = COLLIE_IRQ_GPIO_CF_IRQ,
+       .cd_irq     = COLLIE_IRQ_GPIO_CF_CD,
+       .cd_irq_str = "PCMCIA0 CD",
+},
+};
+
+static struct scoop_pcmcia_config collie_pcmcia_config = {
+       .devs         = &collie_pcmcia_scoop[0],
+       .num_devs     = 1,
+};
+
+
+static struct mcp_plat_data collie_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
+
+static struct sa1100_port_fns collie_port_fns __initdata = {
+       .set_mctrl      = collie_uart_set_mctrl,
+       .get_mctrl      = collie_uart_get_mctrl,
+};
+
 
 static struct resource locomo_resources[] = {
        [0] = {
@@ -159,6 +186,8 @@ static void __init collie_init(void)
        GPDR |= GPIO_32_768kHz;
        TUCR  = TUCR_32_768kHz;
 
+       platform_scoop_config = &collie_pcmcia_config;
+
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        if (ret) {
                printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
@@ -166,6 +195,7 @@ static void __init collie_init(void)
 
        sa11x0_set_flash_data(&collie_flash_data, collie_flash_resources,
                              ARRAY_SIZE(collie_flash_resources));
+       sa11x0_set_mcp_data(&collie_mcp_data);
 
        sharpsl_save_param();
 }
index bfea1bedcbf24af0c2574be0711c3a9f8d05a23b..b008fb0cd7b7faa4c6114d6a49fa632522108edc 100644 (file)
@@ -737,7 +737,7 @@ config PHYSICAL_START
 
 config HOTPLUG_CPU
        bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
-       depends on SMP && HOTPLUG && EXPERIMENTAL && !X86_VOYAGER
+       depends on SMP && HOTPLUG && EXPERIMENTAL && !X86_VOYAGER && !X86_PC
        ---help---
          Say Y here to experiment with turning CPUs off and on.  CPUs
          can be controlled through /sys/devices/system/cpu.
index 00108ba9a78dcef5629ead0e8bea35d0c08c9ea7..6e97df6979e859cd9e82b4c47d40a13f0af197d0 100644 (file)
@@ -44,8 +44,8 @@ comment "Page alloc debug is incompatible with Software Suspend on i386"
        depends on DEBUG_KERNEL && SOFTWARE_SUSPEND
 
 config DEBUG_PAGEALLOC
-       bool "Page alloc debugging"
-       depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND
+       bool "Debug page memory allocations"
+       depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND && !HUGETLBFS
        help
          Unmap pages from the kernel linear mapping after free_pages().
          This results in a large slowdown, but helps to find certain types
index d8d69f2b911d62c909b651de0d9e61a7c7b3b461..4b84ea216f2b81ede738e80206a5fafd8e5ef994 100644 (file)
@@ -76,6 +76,8 @@ edd_mbr_sig_read:
        popw    %es
        popw    %bx
        jc      edd_mbr_sig_done                # on failure, we're done.
+       cmpb    $0, %ah         # some BIOSes do not set CF
+       jne     edd_mbr_sig_done                # on failure, we're done.
        movl    (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
        movl    %eax, (%bx)                     # store success
        incb    (EDD_MBR_SIG_NR_BUF)            # note that we stored something
index 6a93d75db4313a5b3355c0b2896917b13f0c32f8..ca2a0cbcac049883046dc09ba2dd6f0de7c0a9ea 100644 (file)
@@ -106,7 +106,7 @@ static void __init dmi_save_devices(struct dmi_header *dm)
        struct dmi_device *dev;
 
        for (i = 0; i < count; i++) {
-               char *d = ((char *) dm) + (i * 2);
+               char *d = (char *)(dm + 1) + (i * 2);
 
                /* Skip disabled device */
                if ((*d & 0x80) == 0)
index 4c470e99a74202d4afd857e0797dfdfd7ab687a5..82371d83bfa912719c57971980c103b28504cea2 100644 (file)
@@ -1003,7 +1003,6 @@ void cpu_exit_clear(void)
 
        cpu_clear(cpu, cpu_callout_map);
        cpu_clear(cpu, cpu_callin_map);
-       cpu_clear(cpu, cpu_present_map);
 
        cpu_clear(cpu, smp_commenced_mask);
        unmap_cpu_to_logical_apicid(cpu);
@@ -1015,31 +1014,20 @@ struct warm_boot_cpu_info {
        int cpu;
 };
 
-static void __devinit do_warm_boot_cpu(void *p)
+static void __cpuinit do_warm_boot_cpu(void *p)
 {
        struct warm_boot_cpu_info *info = p;
        do_boot_cpu(info->apicid, info->cpu);
        complete(info->complete);
 }
 
-int __devinit smp_prepare_cpu(int cpu)
+static int __cpuinit __smp_prepare_cpu(int cpu)
 {
        DECLARE_COMPLETION(done);
        struct warm_boot_cpu_info info;
        struct work_struct task;
        int     apicid, ret;
 
-       lock_cpu_hotplug();
-
-       /*
-        * On x86, CPU0 is never offlined.  Trying to bring up an
-        * already-booted CPU will hang.  So check for that case.
-        */
-       if (cpu_online(cpu)) {
-               ret = -EINVAL;
-               goto exit;
-       }
-
        apicid = x86_cpu_to_apicid[cpu];
        if (apicid == BAD_APICID) {
                ret = -ENODEV;
@@ -1064,7 +1052,6 @@ int __devinit smp_prepare_cpu(int cpu)
        zap_low_mappings();
        ret = 0;
 exit:
-       unlock_cpu_hotplug();
        return ret;
 }
 #endif
@@ -1392,6 +1379,22 @@ void __cpu_die(unsigned int cpu)
 
 int __devinit __cpu_up(unsigned int cpu)
 {
+#ifdef CONFIG_HOTPLUG_CPU
+       int ret=0;
+
+       /*
+        * We do warm boot only on cpus that had booted earlier
+        * Otherwise cold boot is all handled from smp_boot_cpus().
+        * cpu_callin_map is set during AP kickstart process. Its reset
+        * when a cpu is taken offline from cpu_exit_clear().
+        */
+       if (!cpu_isset(cpu, cpu_callin_map))
+               ret = __smp_prepare_cpu(cpu);
+
+       if (ret)
+               return -EIO;
+#endif
+
        /* In case one didn't come up */
        if (!cpu_isset(cpu, cpu_callin_map)) {
                printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu);
index 70dba1f0e2ee916a7cd032080c96b69e0896ff04..13e739e4c84d9827ca49506175a1fabfb225f1ae 100644 (file)
@@ -1166,19 +1166,7 @@ put_tv32 (struct compat_timeval __user *o, struct timeval *i)
 asmlinkage unsigned long
 sys32_alarm (unsigned int seconds)
 {
-       struct itimerval it_new, it_old;
-       unsigned int oldalarm;
-
-       it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
-       it_new.it_value.tv_sec = seconds;
-       it_new.it_value.tv_usec = 0;
-       do_setitimer(ITIMER_REAL, &it_new, &it_old);
-       oldalarm = it_old.it_value.tv_sec;
-       /* ehhh.. We can't return 0 if we have an alarm pending.. */
-       /* And we'd better return too much than too little anyway */
-       if (it_old.it_value.tv_usec)
-               oldalarm++;
-       return oldalarm;
+       return alarm_setitimer(seconds);
 }
 
 /* Translations due to time_t size differences.  Which affects all
index bbf711bab69e904bc9726314bd27b9df59d2c82b..2e1019ddbb2233667604f312b0597a32a1206a4d 100644 (file)
@@ -19,7 +19,7 @@ config DEBUG_STACK_USAGE
          This option will slow down process creation somewhat.
 
 config DEBUG_PAGEALLOC
-       bool "Page alloc debugging"
+       bool "Debug page memory allocations"
        depends on DEBUG_KERNEL && BROKEN
        help
          Unmap pages from the kernel linear mapping after free_pages().
index 0fc3730a294f245bb0d041500207266a3d195a9d..5407b784cd01abd2a42f769d0c345e75514acfaa 100644 (file)
@@ -645,27 +645,7 @@ static inline void getitimer_real(struct itimerval *value)
 
 asmlinkage unsigned int irix_alarm(unsigned int seconds)
 {
-       struct itimerval it_new, it_old;
-       unsigned int oldalarm;
-
-       if (!seconds) {
-               getitimer_real(&it_old);
-               del_timer(&current->real_timer);
-       } else {
-               it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
-               it_new.it_value.tv_sec = seconds;
-               it_new.it_value.tv_usec = 0;
-               do_setitimer(ITIMER_REAL, &it_new, &it_old);
-       }
-       oldalarm = it_old.it_value.tv_sec;
-       /*
-        * ehhh.. We can't return 0 if we have an alarm pending ...
-        * And we'd better return too much than too little anyway
-        */
-       if (it_old.it_value.tv_usec)
-               oldalarm++;
-
-       return oldalarm;
+       return alarm_setitimer(seconds);
 }
 
 asmlinkage int irix_pause(void)
index 49eb2a7e65c0711a8ee2585b0ec2221210796c5a..a892356d5c3b66cf6bbd34dffd2657058ef9ee96 100644 (file)
@@ -126,11 +126,11 @@ static int numReadBufs = 4, readbufSize = 32;
 */
 static volatile cbd_t  *rx_base, *rx_cur, *tx_base, *tx_cur;
 
-MODULE_PARM(catchRadius, "i");
-MODULE_PARM(numBufs, "i");
-MODULE_PARM(bufSize, "i");
-MODULE_PARM(numreadBufs, "i");
-MODULE_PARM(readbufSize, "i");
+module_param(catchRadius, int, 0);
+module_param(numBufs, int, 0);
+module_param(bufSize, int, 0);
+module_param(numreadBufs, int, 0);
+module_param(readbufSize, int, 0);
 
 #define arraysize(x)   (sizeof(x)/sizeof(*(x)))
 #define le2be16(x)     (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
index f944b58cdfe79fde99ab07fc2348f2af059875f6..7c58fc1a39c46ae6f7bab2aeb57ffafcf495b12d 100644 (file)
@@ -23,7 +23,6 @@ menu "General machine setup"
 
 config SMP
        bool "Symmetric multi-processing support (does not work on sun4/sun4c)"
-       depends on BROKEN
        ---help---
          This enables support for systems with more than one CPU. If you have
          a system with only one CPU, say N. If you have a system with more
index 4c60a6ef54a9157e0ae0d42770ea3acde6ded729..aac8af5aae51ddcea1a954ee7876b104c2d40576 100644 (file)
@@ -154,9 +154,11 @@ void (*sparc_init_timers)(irqreturn_t (*)(int, void *,struct pt_regs *)) =
 struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 int static_irq_count;
 
-struct irqaction *irq_action[NR_IRQS] = {
-       [0 ... (NR_IRQS-1)] = NULL
-};
+struct {
+       struct irqaction *action;
+       int flags;
+} sparc_irq[NR_IRQS];
+#define SPARC_IRQ_INPROGRESS 1
 
 /* Used to protect the IRQ action lists */
 DEFINE_SPINLOCK(irq_action_lock);
@@ -177,7 +179,7 @@ int show_interrupts(struct seq_file *p, void *v)
        }
        spin_lock_irqsave(&irq_action_lock, flags);
        if (i < NR_IRQS) {
-               action = *(i + irq_action);
+               action = sparc_irq[i].action;
                if (!action) 
                        goto out_unlock;
                seq_printf(p, "%3d: ", i);
@@ -186,7 +188,7 @@ int show_interrupts(struct seq_file *p, void *v)
 #else
                for_each_online_cpu(j) {
                        seq_printf(p, "%10u ",
-                                   kstat_cpu(cpu_logical_map(j)).irqs[i]);
+                                   kstat_cpu(j).irqs[i]);
                }
 #endif
                seq_printf(p, " %c %s",
@@ -207,7 +209,7 @@ out_unlock:
 void free_irq(unsigned int irq, void *dev_id)
 {
        struct irqaction * action;
-       struct irqaction * tmp = NULL;
+       struct irqaction **actionp;
         unsigned long flags;
        unsigned int cpu_irq;
        
@@ -225,7 +227,8 @@ void free_irq(unsigned int irq, void *dev_id)
 
        spin_lock_irqsave(&irq_action_lock, flags);
 
-       action = *(cpu_irq + irq_action);
+       actionp = &sparc_irq[cpu_irq].action;
+       action = *actionp;
 
        if (!action->handler) {
                printk("Trying to free free IRQ%d\n",irq);
@@ -235,7 +238,7 @@ void free_irq(unsigned int irq, void *dev_id)
                for (; action; action = action->next) {
                        if (action->dev_id == dev_id)
                                break;
-                       tmp = action;
+                       actionp = &action->next;
                }
                if (!action) {
                        printk("Trying to free free shared IRQ%d\n",irq);
@@ -254,11 +257,8 @@ void free_irq(unsigned int irq, void *dev_id)
                       irq, action->name);
                goto out_unlock;
        }
-       
-       if (action && tmp)
-               tmp->next = action->next;
-       else
-               *(cpu_irq + irq_action) = action->next;
+
+       *actionp = action->next;
 
        spin_unlock_irqrestore(&irq_action_lock, flags);
 
@@ -268,7 +268,7 @@ void free_irq(unsigned int irq, void *dev_id)
 
        kfree(action);
 
-       if (!(*(cpu_irq + irq_action)))
+       if (!sparc_irq[cpu_irq].action)
                disable_irq(irq);
 
 out_unlock:
@@ -287,8 +287,11 @@ EXPORT_SYMBOL(free_irq);
 #ifdef CONFIG_SMP
 void synchronize_irq(unsigned int irq)
 {
-       printk("synchronize_irq says: implement me!\n");
-       BUG();
+       unsigned int cpu_irq;
+
+       cpu_irq = irq & (NR_IRQS - 1);
+       while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS)
+               cpu_relax();
 }
 #endif /* SMP */
 
@@ -299,7 +302,7 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
        unsigned int cpu_irq;
        
        cpu_irq = irq & (NR_IRQS - 1);
-       action = *(cpu_irq + irq_action);
+       action = sparc_irq[cpu_irq].action;
 
         printk("IO device interrupt, irq = %d\n", irq);
         printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
@@ -330,7 +333,8 @@ void handler_irq(int irq, struct pt_regs * regs)
        if(irq < 10)
                smp4m_irq_rotate(cpu);
 #endif
-       action = *(irq + irq_action);
+       action = sparc_irq[irq].action;
+       sparc_irq[irq].flags |= SPARC_IRQ_INPROGRESS;
        kstat_cpu(cpu).irqs[irq]++;
        do {
                if (!action || !action->handler)
@@ -338,6 +342,7 @@ void handler_irq(int irq, struct pt_regs * regs)
                action->handler(irq, action->dev_id, regs);
                action = action->next;
        } while (action);
+       sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS;
        enable_pil_irq(irq);
        irq_exit();
 }
@@ -389,7 +394,7 @@ int request_fast_irq(unsigned int irq,
 
        spin_lock_irqsave(&irq_action_lock, flags);
 
-       action = *(cpu_irq + irq_action);
+       action = sparc_irq[cpu_irq].action;
        if(action) {
                if(action->flags & SA_SHIRQ)
                        panic("Trying to register fast irq when already shared.\n");
@@ -452,7 +457,7 @@ int request_fast_irq(unsigned int irq,
        action->dev_id = NULL;
        action->next = NULL;
 
-       *(cpu_irq + irq_action) = action;
+       sparc_irq[cpu_irq].action = action;
 
        enable_irq(irq);
 
@@ -467,7 +472,7 @@ int request_irq(unsigned int irq,
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
                unsigned long irqflags, const char * devname, void *dev_id)
 {
-       struct irqaction * action, *tmp = NULL;
+       struct irqaction * action, **actionp;
        unsigned long flags;
        unsigned int cpu_irq;
        int ret;
@@ -490,20 +495,20 @@ int request_irq(unsigned int irq,
            
        spin_lock_irqsave(&irq_action_lock, flags);
 
-       action = *(cpu_irq + irq_action);
+       actionp = &sparc_irq[cpu_irq].action;
+       action = *actionp;
        if (action) {
-               if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-                       for (tmp = action; tmp->next; tmp = tmp->next);
-               } else {
+               if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) {
                        ret = -EBUSY;
                        goto out_unlock;
                }
-               if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+               if ((action->flags & SA_INTERRUPT) != (irqflags & SA_INTERRUPT)) {
                        printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
                        ret = -EBUSY;
                        goto out_unlock;
-               }   
-               action = NULL;          /* Or else! */
+               }
+               for ( ; action; action = *actionp)
+                       actionp = &action->next;
        }
 
        /* If this is flagged as statically allocated then we use our
@@ -532,10 +537,7 @@ int request_irq(unsigned int irq,
        action->next = NULL;
        action->dev_id = dev_id;
 
-       if (tmp)
-               tmp->next = action;
-       else
-               *(cpu_irq + irq_action) = action;
+       *actionp = action;
 
        enable_irq(irq);
 
index ea5682ce70319c99ee3ae994685287d54413a357..2be8121151977d4404cb0976ca445786ba5621b7 100644 (file)
@@ -45,6 +45,7 @@ volatile int __cpu_logical_map[NR_CPUS];
 
 cpumask_t cpu_online_map = CPU_MASK_NONE;
 cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+cpumask_t smp_commenced_mask = CPU_MASK_NONE;
 
 /* The only guaranteed locking primitive available on all Sparc
  * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
@@ -57,11 +58,6 @@ cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
 /* Used to make bitops atomic */
 unsigned char bitops_spinlock = 0;
 
-volatile unsigned long ipi_count;
-
-volatile int smp_process_available=0;
-volatile int smp_commenced = 0;
-
 void __init smp_store_cpu_info(int id)
 {
        int cpu_node;
@@ -79,6 +75,22 @@ void __init smp_store_cpu_info(int id)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
+       extern void smp4m_smp_done(void);
+       unsigned long bogosum = 0;
+       int cpu, num;
+
+       for (cpu = 0, num = 0; cpu < NR_CPUS; cpu++)
+               if (cpu_online(cpu)) {
+                       num++;
+                       bogosum += cpu_data(cpu).udelay_val;
+               }
+
+       printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+               num, bogosum/(500000/HZ),
+               (bogosum/(5000/HZ))%100);
+
+       BUG_ON(sparc_cpu_model != sun4m);
+       smp4m_smp_done();
 }
 
 void cpu_panic(void)
@@ -89,17 +101,6 @@ void cpu_panic(void)
 
 struct linux_prom_registers smp_penguin_ctable __initdata = { 0 };
 
-void __init smp_boot_cpus(void)
-{
-       extern void smp4m_boot_cpus(void);
-       extern void smp4d_boot_cpus(void);
-       
-       if (sparc_cpu_model == sun4m)
-               smp4m_boot_cpus();
-       else
-               smp4d_boot_cpus();
-}
-
 void smp_send_reschedule(int cpu)
 {
        /* See sparc64 */
@@ -252,20 +253,61 @@ int setup_profiling_timer(unsigned int multiplier)
        return 0;
 }
 
-void __init smp_prepare_cpus(unsigned int maxcpus)
+void __init smp_prepare_cpus(unsigned int max_cpus)
 {
+       extern void smp4m_boot_cpus(void);
+       int i, cpuid, ncpus, extra;
+
+       BUG_ON(sparc_cpu_model != sun4m);
+       printk("Entering SMP Mode...\n");
+
+       ncpus = 1;
+       extra = 0;
+       for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) {
+               if (cpuid == boot_cpu_id)
+                       continue;
+               if (cpuid < NR_CPUS && ncpus++ < max_cpus)
+                       cpu_set(cpuid, phys_cpu_present_map);
+               else
+                       extra++;
+       }
+       if (max_cpus >= NR_CPUS && extra)
+               printk("Warning: NR_CPUS is too low to start all cpus\n");
+
+       smp_store_cpu_info(boot_cpu_id);
+
+       smp4m_boot_cpus();
 }
 
 void __devinit smp_prepare_boot_cpu(void)
 {
-       current_thread_info()->cpu = hard_smp_processor_id();
-       cpu_set(smp_processor_id(), cpu_online_map);
-       cpu_set(smp_processor_id(), phys_cpu_present_map);
+       int cpuid = hard_smp_processor_id();
+
+       if (cpuid >= NR_CPUS) {
+               prom_printf("Serious problem, boot cpu id >= NR_CPUS\n");
+               prom_halt();
+       }
+       if (cpuid != 0)
+               printk("boot cpu id != 0, this could work but is untested\n");
+
+       current_thread_info()->cpu = cpuid;
+       cpu_set(cpuid, cpu_online_map);
+       cpu_set(cpuid, phys_cpu_present_map);
 }
 
 int __devinit __cpu_up(unsigned int cpu)
 {
-       panic("smp doesn't work\n");
+       extern int smp4m_boot_one_cpu(int);
+       int ret;
+
+       ret = smp4m_boot_one_cpu(cpu);
+
+       if (!ret) {
+               cpu_set(cpu, smp_commenced_mask);
+               while (!cpu_online(cpu))
+                       mb();
+       }
+       return ret;
 }
 
 void smp_bogo(struct seq_file *m)
index 19b25399d7e4219ad862863b0f941159ac195ba9..2c21d79076356e2a0c617bb290109fd8705f92b2 100644 (file)
@@ -136,10 +136,6 @@ EXPORT_PER_CPU_SYMBOL(__cpu_data);
 /* IRQ implementation. */
 EXPORT_SYMBOL(synchronize_irq);
 
-/* Misc SMP information */
-EXPORT_SYMBOL(__cpu_number_map);
-EXPORT_SYMBOL(__cpu_logical_map);
-
 /* CPU online map and active count. */
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(phys_cpu_present_map);
index cea7fc6fc6e5b2ddf376f1481e695a114158ead1..ca656d9bd6fd92d8dcccbb39ec75df1c16c74d16 100644 (file)
@@ -54,7 +54,7 @@ unsigned char cpu_leds[32];
 unsigned char sbus_tid[32];
 #endif
 
-extern struct irqaction *irq_action[];
+static struct irqaction *irq_action[NR_IRQS];
 extern spinlock_t irq_action_lock;
 
 struct sbus_action {
index 41bb9596be48f443f57c66e5575739dab246d6ed..b141b7ee6717751751743587cd9072f68390ffc4 100644 (file)
@@ -46,14 +46,16 @@ extern volatile int smp_processors_ready;
 extern int smp_num_cpus;
 static int smp_highest_cpu;
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern cpuinfo_sparc cpu_data[NR_CPUS];
 extern unsigned char boot_cpu_id;
 extern int smp_activated;
 extern volatile int __cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
 extern volatile unsigned long ipi_count;
 extern volatile int smp_process_available;
-extern volatile int smp_commenced;
+
+extern cpumask_t smp_commenced_mask;
+
 extern int __smp4d_processor_id(void);
 
 /* #define SMP_DEBUG */
@@ -136,7 +138,7 @@ void __init smp4d_callin(void)
        
        local_irq_enable();     /* We don't allow PIL 14 yet */
        
-       while(!smp_commenced)
+       while (!cpu_isset(cpuid, smp_commenced_mask))
                barrier();
 
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
index 1dde312eebda7ec16b58b09fa80c9d0780e13091..70b375a4c2c2b2b38fdd040c369282815a4d186d 100644 (file)
@@ -40,15 +40,11 @@ extern ctxd_t *srmmu_ctx_table_phys;
 extern void calibrate_delay(void);
 
 extern volatile int smp_processors_ready;
-extern int smp_num_cpus;
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
 extern unsigned char boot_cpu_id;
-extern int smp_activated;
-extern volatile int __cpu_number_map[NR_CPUS];
-extern volatile int __cpu_logical_map[NR_CPUS];
-extern volatile unsigned long ipi_count;
-extern volatile int smp_process_available;
-extern volatile int smp_commenced;
+
+extern cpumask_t smp_commenced_mask;
+
 extern int __smp4m_processor_id(void);
 
 /*#define SMP_DEBUG*/
@@ -77,8 +73,6 @@ void __init smp4m_callin(void)
        local_flush_cache_all();
        local_flush_tlb_all();
 
-       set_irq_udt(boot_cpu_id);
-
        /* Get our local ticker going. */
        smp_setup_percpu_timer();
 
@@ -95,8 +89,9 @@ void __init smp4m_callin(void)
         * to call the scheduler code.
         */
        /* Allow master to continue. */
-       swap((unsigned long *)&cpu_callin_map[cpuid], 1);
+       swap(&cpu_callin_map[cpuid], 1);
 
+       /* XXX: What's up with all the flushes? */
        local_flush_cache_all();
        local_flush_tlb_all();
        
@@ -111,13 +106,14 @@ void __init smp4m_callin(void)
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
 
-       while(!smp_commenced)
-               barrier();
-
-       local_flush_cache_all();
-       local_flush_tlb_all();
+       while (!cpu_isset(cpuid, smp_commenced_mask))
+               mb();
 
        local_irq_enable();
+
+       cpu_set(cpuid, cpu_online_map);
+       /* last one in gets all the interrupts (for testing) */
+       set_irq_udt(boot_cpu_id);
 }
 
 extern void init_IRQ(void);
@@ -134,102 +130,76 @@ extern unsigned long trapbase_cpu3[];
 
 void __init smp4m_boot_cpus(void)
 {
-       int cpucount = 0;
-       int i, mid;
+       smp_setup_percpu_timer();
+       local_flush_cache_all();
+}
 
-       printk("Entering SMP Mode...\n");
+int smp4m_boot_one_cpu(int i)
+{
+       extern unsigned long sun4m_cpu_startup;
+       unsigned long *entry = &sun4m_cpu_startup;
+       struct task_struct *p;
+       int timeout;
+       int cpu_node;
 
-       local_irq_enable();
-       cpus_clear(cpu_present_map);
+       cpu_find_by_mid(i, &cpu_node);
+
+       /* Cook up an idler for this guy. */
+       p = fork_idle(i);
+       current_set[i] = task_thread_info(p);
+       /* See trampoline.S for details... */
+       entry += ((i-1) * 3);
 
-       for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
-               cpu_set(mid, cpu_present_map);
+       /*
+        * Initialize the contexts table
+        * Since the call to prom_startcpu() trashes the structure,
+        * we need to re-initialize it for each cpu
+        */
+       smp_penguin_ctable.which_io = 0;
+       smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+       smp_penguin_ctable.reg_size = 0;
 
-       for(i=0; i < NR_CPUS; i++) {
-               __cpu_number_map[i] = -1;
-               __cpu_logical_map[i] = -1;
+       /* whirrr, whirrr, whirrrrrrrrr... */
+       printk("Starting CPU %d at %p\n", i, entry);
+       local_flush_cache_all();
+       prom_startcpu(cpu_node,
+                     &smp_penguin_ctable, 0, (char *)entry);
+
+       /* wheee... it's going... */
+       for(timeout = 0; timeout < 10000; timeout++) {
+               if(cpu_callin_map[i])
+                       break;
+               udelay(200);
        }
 
-       __cpu_number_map[boot_cpu_id] = 0;
-       __cpu_logical_map[0] = boot_cpu_id;
-       current_thread_info()->cpu = boot_cpu_id;
+       if (!(cpu_callin_map[i])) {
+               printk("Processor %d is stuck.\n", i);
+               return -ENODEV;
+       }
 
-       smp_store_cpu_info(boot_cpu_id);
-       set_irq_udt(boot_cpu_id);
-       smp_setup_percpu_timer();
        local_flush_cache_all();
-       if(cpu_find_by_instance(1, NULL, NULL))
-               return;  /* Not an MP box. */
-       for(i = 0; i < NR_CPUS; i++) {
-               if(i == boot_cpu_id)
-                       continue;
-
-               if (cpu_isset(i, cpu_present_map)) {
-                       extern unsigned long sun4m_cpu_startup;
-                       unsigned long *entry = &sun4m_cpu_startup;
-                       struct task_struct *p;
-                       int timeout;
-
-                       /* Cook up an idler for this guy. */
-                       p = fork_idle(i);
-                       cpucount++;
-                       current_set[i] = task_thread_info(p);
-                       /* See trampoline.S for details... */
-                       entry += ((i-1) * 3);
-
-                       /*
-                        * Initialize the contexts table
-                        * Since the call to prom_startcpu() trashes the structure,
-                        * we need to re-initialize it for each cpu
-                        */
-                       smp_penguin_ctable.which_io = 0;
-                       smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
-                       smp_penguin_ctable.reg_size = 0;
-
-                       /* whirrr, whirrr, whirrrrrrrrr... */
-                       printk("Starting CPU %d at %p\n", i, entry);
-                       local_flush_cache_all();
-                       prom_startcpu(cpu_data(i).prom_node,
-                                     &smp_penguin_ctable, 0, (char *)entry);
-
-                       /* wheee... it's going... */
-                       for(timeout = 0; timeout < 10000; timeout++) {
-                               if(cpu_callin_map[i])
-                                       break;
-                               udelay(200);
-                       }
-                       if(cpu_callin_map[i]) {
-                               /* Another "Red Snapper". */
-                               __cpu_number_map[i] = i;
-                               __cpu_logical_map[i] = i;
-                       } else {
-                               cpucount--;
-                               printk("Processor %d is stuck.\n", i);
-                       }
-               }
-               if(!(cpu_callin_map[i])) {
-                       cpu_clear(i, cpu_present_map);
-                       __cpu_number_map[i] = -1;
+       return 0;
+}
+
+void __init smp4m_smp_done(void)
+{
+       int i, first;
+       int *prev;
+
+       /* setup cpu list for irq rotation */
+       first = 0;
+       prev = &first;
+       for (i = 0; i < NR_CPUS; i++) {
+               if (cpu_online(i)) {
+                       *prev = i;
+                       prev = &cpu_data(i).next;
                }
        }
+       *prev = first;
        local_flush_cache_all();
-       if(cpucount == 0) {
-               printk("Error: only one Processor found.\n");
-               cpu_present_map = cpumask_of_cpu(smp_processor_id());
-       } else {
-               unsigned long bogosum = 0;
-               for_each_present_cpu(i)
-                       bogosum += cpu_data(i).udelay_val;
-               printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
-                      cpucount + 1,
-                      bogosum/(500000/HZ),
-                      (bogosum/(5000/HZ))%100);
-               smp_activated = 1;
-               smp_num_cpus = cpucount + 1;
-       }
 
        /* Free unneeded trap tables */
-       if (!cpu_isset(i, cpu_present_map)) {
+       if (!cpu_isset(1, cpu_present_map)) {
                ClearPageReserved(virt_to_page(trapbase_cpu1));
                init_page_count(virt_to_page(trapbase_cpu1));
                free_page((unsigned long)trapbase_cpu1);
@@ -263,6 +233,9 @@ void __init smp4m_boot_cpus(void)
  */
 void smp4m_irq_rotate(int cpu)
 {
+       int next = cpu_data(cpu).next;
+       if (next != cpu)
+               set_irq_udt(next);
 }
 
 /* Cross calls, in order to work efficiently and atomically do all
@@ -289,7 +262,7 @@ void smp4m_message_pass(int target, int msg, unsigned long data, int wait)
 
        smp_cpu_in_msg[me]++;
        if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) {
-               mask = cpu_present_map;
+               mask = cpu_online_map;
                if(target == MSG_ALL_BUT_SELF)
                        cpu_clear(me, mask);
                for(i = 0; i < 4; i++) {
@@ -314,8 +287,8 @@ static struct smp_funcall {
        unsigned long arg3;
        unsigned long arg4;
        unsigned long arg5;
-       unsigned long processors_in[NR_CPUS];  /* Set when ipi entered. */
-       unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
+       unsigned long processors_in[SUN4M_NCPUS];  /* Set when ipi entered. */
+       unsigned long processors_out[SUN4M_NCPUS]; /* Set when ipi exited. */
 } ccall_info;
 
 static DEFINE_SPINLOCK(cross_call_lock);
@@ -324,8 +297,7 @@ static DEFINE_SPINLOCK(cross_call_lock);
 void smp4m_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
                    unsigned long arg3, unsigned long arg4, unsigned long arg5)
 {
-       if(smp_processors_ready) {
-               register int ncpus = smp_num_cpus;
+               register int ncpus = SUN4M_NCPUS;
                unsigned long flags;
 
                spin_lock_irqsave(&cross_call_lock, flags);
@@ -340,7 +312,7 @@ void smp4m_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
 
                /* Init receive/complete mapping, plus fire the IPI's off. */
                {
-                       cpumask_t mask = cpu_present_map;
+                       cpumask_t mask = cpu_online_map;
                        register int i;
 
                        cpu_clear(smp_processor_id(), mask);
@@ -373,7 +345,6 @@ void smp4m_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
                }
 
                spin_unlock_irqrestore(&cross_call_lock, flags);
-       }
 }
 
 /* Running cross calls. */
index 27b0e0ba8581ec2214b2197531432455e46e12b1..58c65cc8d0d34545b0c587a19ffcff9ed04ba80d 100644 (file)
@@ -1302,7 +1302,12 @@ void __init srmmu_paging_init(void)
 
        flush_cache_all();
        srmmu_set_ctable_ptr((unsigned long)srmmu_ctx_table_phys);
+#ifdef CONFIG_SMP
+       /* Stop from hanging here... */
+       local_flush_tlb_all();
+#else
        flush_tlb_all();
+#endif
        poke_srmmu();
 
 #ifdef CONFIG_SUN_IO
@@ -1419,6 +1424,7 @@ static void __init init_vac_layout(void)
                                max_size = vac_cache_size;
                        if(vac_line_size < min_line_size)
                                min_line_size = vac_line_size;
+                       //FIXME: cpus not contiguous!!
                        cpu++;
                        if (cpu >= NR_CPUS || !cpu_online(cpu))
                                break;
index 3e31be494e54ab7902d4df0639ce0bdab8ffe559..afe0a7720a26492d08e52b40862817c5ac658081 100644 (file)
@@ -24,7 +24,7 @@ config DEBUG_BOOTMEM
        bool "Debug BOOTMEM initialization"
 
 config DEBUG_PAGEALLOC
-       bool "Page alloc debugging"
+       bool "Debug page memory allocations"
        depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND
        help
          Unmap pages from the kernel linear mapping after free_pages().
index 2bc55af9541922aa1163790cb27c6cb8df84d6dc..2b2d029f477ca4866caace5da4950fd5a17fa490 100644 (file)
@@ -430,24 +430,12 @@ put_tv32(struct compat_timeval __user *o, struct timeval *i)
        return err; 
 }
 
-extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+extern unsigned int alarm_setitimer(unsigned int seconds);
 
 asmlinkage long
 sys32_alarm(unsigned int seconds)
 {
-       struct itimerval it_new, it_old;
-       unsigned int oldalarm;
-
-       it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
-       it_new.it_value.tv_sec = seconds;
-       it_new.it_value.tv_usec = 0;
-       do_setitimer(ITIMER_REAL, &it_new, &it_old);
-       oldalarm = it_old.it_value.tv_sec;
-       /* ehhh.. We can't return 0 if we have an alarm pending.. */
-       /* And we'd better return too much than too little anyway */
-       if (it_old.it_value.tv_usec)
-               oldalarm++;
-       return oldalarm;
+       return alarm_setitimer(seconds);
 }
 
 /* Translations due to time_t size differences.  Which affects all
index 29f3d7504da1fd797d8753f644e0b408ef2a8b19..dd712b24ec91900f3b75506af6ecf6467f7ba160 100644 (file)
@@ -19,11 +19,6 @@ EXPORT_SYMBOL(cpu_sysdev_class);
 static struct sys_device *cpu_sys_devices[NR_CPUS];
 
 #ifdef CONFIG_HOTPLUG_CPU
-int __attribute__((weak)) smp_prepare_cpu (int cpu)
-{
-       return 0;
-}
-
 static ssize_t show_online(struct sys_device *dev, char *buf)
 {
        struct cpu *cpu = container_of(dev, struct cpu, sysdev);
@@ -44,9 +39,7 @@ static ssize_t store_online(struct sys_device *dev, const char *buf,
                        kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
                break;
        case '1':
-               ret = smp_prepare_cpu(cpu->sysdev.id);
-               if (!ret)
-                       ret = cpu_up(cpu->sysdev.id);
+               ret = cpu_up(cpu->sysdev.id);
                if (!ret)
                        kobject_uevent(&dev->kobj, KOBJ_ONLINE);
                break;
index 8b133167740768c6ac96071a356a7c8fd1046ac6..e57ac5a432462bc2ef4c3323f329808ab0f107ca 100644 (file)
@@ -401,7 +401,6 @@ config BLK_DEV_RAM_SIZE
 
 config BLK_DEV_INITRD
        bool "Initial RAM disk (initrd) support"
-       depends on BLK_DEV_RAM=y
        help
          The initial RAM disk is a RAM disk that is loaded by the boot loader
          (loadlin or lilo) and that is mounted as root before the normal boot
index f8ce235ccfc3b4e4ba65169e6ec3046c5fd0b67e..c39650920bdf7ff85be4be0455ea11965dbea9b0 100644 (file)
@@ -271,7 +271,7 @@ unsigned char *DMABuffer;                     /* buffer for writes */
 static unsigned long PhysDMABuffer;   /* physical address */
 
 static int UseTrackbuffer = -1;                  /* Do track buffering? */
-MODULE_PARM(UseTrackbuffer, "i");
+module_param(UseTrackbuffer, int, 0);
 
 unsigned char *TrackBuffer;                      /* buffer for reads */
 static unsigned long PhysTrackBuffer; /* physical address */
@@ -296,7 +296,7 @@ static int MotorOn = 0, MotorOffTrys;
 static int IsFormatting = 0, FormatError;
 
 static int UserSteprate[FD_MAX_UNITS] = { -1, -1 };
-MODULE_PARM(UserSteprate, "1-" __MODULE_STRING(FD_MAX_UNITS) "i");
+module_param_array(UserSteprate, int, NULL, 0);
 
 /* Synchronization of FDC access. */
 static volatile int fdc_busy = 0;
index fb2d0be7cdebb21444f6b978f7c0ea4d82895579..840919bba76cc146df23ef736cd45b318b0e2d9c 100644 (file)
@@ -4594,7 +4594,7 @@ static void __init parse_floppy_cfg_string(char *cfg)
        }
 }
 
-int init_module(void)
+int __init init_module(void)
 {
        if (floppy)
                parse_floppy_cfg_string(floppy);
index a9bde30dadad5021e1c2a35965c825d34ac1e9a7..8bca4905d7f7357e31b8d66f53a79fc79379c874 100644 (file)
@@ -639,10 +639,7 @@ static int __init nbd_init(void)
        int err = -ENOMEM;
        int i;
 
-       if (sizeof(struct nbd_request) != 28) {
-               printk(KERN_CRIT "nbd: sizeof nbd_request needs to be 28 in order to work!\n" );
-               return -EIO;
-       }
+       BUILD_BUG_ON(sizeof(struct nbd_request) != 28);
 
        if (nbds_max > MAX_NBD) {
                printk(KERN_CRIT "nbd: cannot allocate more than %u nbds; %u requested.\n", MAX_NBD,
index fad27a87ce35af5f4d01fc20df5c3f777f851554..f43a988dd413e0cc9fbdbf2db9e9fef04f2c948d 100644 (file)
@@ -218,12 +218,12 @@ static int cm206_base = CM206_BASE;
 static int cm206_irq = CM206_IRQ;
 #ifdef MODULE
 static int cm206[2] = { 0, 0 };        /* for compatible `insmod' parameter passing */
+module_param_array(cm206, int, NULL, 0);       /* base,irq or irq,base */
 #endif
 
-MODULE_PARM(cm206_base, "i");  /* base */
-MODULE_PARM(cm206_irq, "i");   /* irq */
-MODULE_PARM(cm206, "1-2i");    /* base,irq or irq,base */
-MODULE_PARM(auto_probe, "i");  /* auto probe base and irq */
+module_param(cm206_base, int, 0);      /* base */
+module_param(cm206_irq, int, 0);       /* irq */
+module_param(auto_probe, bool, 0);     /* auto probe base and irq */
 MODULE_LICENSE("GPL");
 
 #define POLLOOP 100            /* milliseconds */
index 4760f515f59149c3423badf6bee586bc9e44dffc..05c9e865ecaf85a33eafa3be2cfe0bb837a71148 100644 (file)
@@ -464,8 +464,13 @@ static int sbpcd[] =
 static  __cacheline_aligned DEFINE_SPINLOCK(sbpcd_lock);
 static struct request_queue *sbpcd_queue;
 
-MODULE_PARM(sbpcd, "2i");
-MODULE_PARM(max_drives, "i");
+/* You can only set the first pair, from old MODULE_PARM code.  */
+static int sbpcd_set(const char *val, struct kernel_param *kp)
+{
+       get_options((char *)val, 2, (int *)sbpcd);
+       return 0;
+}
+module_param_call(sbpcd, sbpcd_set, NULL, NULL, 0);
 
 #define NUM_PROBE  (sizeof(sbpcd) / sizeof(int))
 
@@ -553,6 +558,7 @@ static unsigned char msgnum;
 static char msgbuf[80];
 
 static int max_drives = MAX_DRIVES;
+module_param(max_drives, int, 0);
 #ifndef MODULE
 static unsigned char setup_done;
 static const char *str_sb_l = "soundblaster";
index d745004281d08f372aaa0bdc87f0e231b946651e..abd4c5118a1b52f4e901c6d30ce54df381a97371 100644 (file)
@@ -736,7 +736,8 @@ int ipmi_create_user(unsigned int          if_num,
        intf = ipmi_interfaces[if_num];
        if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) {
                spin_unlock_irqrestore(&interfaces_lock, flags);
-               return -EINVAL;
+               rv = -EINVAL;
+               goto out_kfree;
        }
 
        /* Note that each existing user holds a refcount to the interface. */
@@ -751,14 +752,14 @@ int ipmi_create_user(unsigned int          if_num,
 
        if (!try_module_get(intf->handlers->owner)) {
                rv = -ENODEV;
-               goto out_err;
+               goto out_kref;
        }
 
        if (intf->handlers->inc_usecount) {
                rv = intf->handlers->inc_usecount(intf->send_info);
                if (rv) {
                        module_put(intf->handlers->owner);
-                       goto out_err;
+                       goto out_kref;
                }
        }
 
@@ -769,9 +770,10 @@ int ipmi_create_user(unsigned int          if_num,
        *user = new_user;
        return 0;
 
- out_err:
-       kfree(new_user);
+out_kref:
        kref_put(&intf->refcount, intf_free);
+out_kfree:
+       kfree(new_user);
        return rv;
 }
 
index ede128356af23c0fc23ecd05c9f6bf384cdc6372..e5247f85a446e4003a4bd81733d23f3f6ac8e82a 100644 (file)
@@ -378,13 +378,13 @@ MODULE_DESCRIPTION("Stallion Intelligent Multiport Serial Driver");
 MODULE_LICENSE("GPL");
 
 
-MODULE_PARM(board0, "1-3s");
+module_param_array(board0, charp, NULL, 0);
 MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,memaddr]");
-MODULE_PARM(board1, "1-3s");
+module_param_array(board1, charp, NULL, 0);
 MODULE_PARM_DESC(board1, "Board 1 config -> name[,ioaddr[,memaddr]");
-MODULE_PARM(board2, "1-3s");
+module_param_array(board2, charp, NULL, 0);
 MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,memaddr]");
-MODULE_PARM(board3, "1-3s");
+module_param_array(board3, charp, NULL, 0);
 MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]");
 
 #endif
index 29c41f4418c065d9aa8a447ae34f984e2cf3f321..26d0116b48d43a9d2a422c9489d7910754752132 100644 (file)
@@ -216,11 +216,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
 
                copied = copy_from_user(ptr, buf, sz);
                if (copied) {
-                       ssize_t ret;
-
-                       ret = written + (sz - copied);
-                       if (ret)
-                               return ret;
+                       written += sz - copied;
+                       if (written)
+                               break;
                        return -EFAULT;
                }
                buf += sz;
@@ -456,11 +454,9 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf,
 
                copied = copy_from_user(ptr, buf, sz);
                if (copied) {
-                       ssize_t ret;
-
-                       ret = written + (sz - copied);
-                       if (ret)
-                               return ret;
+                       written += sz - copied;
+                       if (written)
+                               break;
                        return -EFAULT;
                }
                buf += sz;
@@ -514,11 +510,10 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
                        if (len) {
                                written = copy_from_user(kbuf, buf, len);
                                if (written) {
-                                       ssize_t ret;
-
+                                       if (wrote + virtr)
+                                               break;
                                        free_page((unsigned long)kbuf);
-                                       ret = wrote + virtr + (len - written);
-                                       return ret ? ret : -EFAULT;
+                                       return -EFAULT;
                                }
                        }
                        len = vwrite(kbuf, (char *)p, len);
@@ -563,8 +558,11 @@ static ssize_t write_port(struct file * file, const char __user * buf,
                return -EFAULT;
        while (count-- > 0 && i < 65536) {
                char c;
-               if (__get_user(c, tmp)) 
+               if (__get_user(c, tmp)) {
+                       if (tmp > buf)
+                               break;
                        return -EFAULT; 
+               }
                outb(c,i);
                i++;
                tmp++;
index ea725a9964e2007075db5e814422ceed52f84ee3..0fb2fb9fb024b6e9a85ad241105e29b5a6e49a68 100644 (file)
@@ -243,10 +243,10 @@ static int verbose = 0;
 
 MODULE_AUTHOR("Casper Yang");
 MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
-MODULE_PARM(ioaddr, "1-4i");
-MODULE_PARM(ttymajor, "i");
-MODULE_PARM(calloutmajor, "i");
-MODULE_PARM(verbose, "i");
+module_param_array(ioaddr, int, NULL, 0);
+module_param(ttymajor, int, 0);
+module_param(calloutmajor, int, 0);
+module_param(verbose, bool, 0);
 MODULE_LICENSE("GPL");
 
 struct mxser_log {
index 306ee0f091a4eb6e3920f5cea458b9a616b6ac59..bee6c47b45bdd162e33e50e32171667dd6df8df8 100644 (file)
 #include <linux/parport.h>
 #include <linux/ctype.h>
 #include <linux/poll.h>
-#include <asm/uaccess.h>
+#include <linux/major.h>
 #include <linux/ppdev.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
+#include <asm/uaccess.h>
 
 #define PP_VERSION "ppdev: user-space parallel port driver"
 #define CHRDEV "ppdev"
index 119e629656b7b4d5e835ec1fe11a423a4f35c258..657c0d88f48c439e6788e4bf4d9bc2e24c1a5550 100644 (file)
@@ -1743,10 +1743,10 @@ static int iobase;
 static int iobase1;
 static int iobase2;
 static int iobase3;
-MODULE_PARM(iobase, "i");
-MODULE_PARM(iobase1, "i");
-MODULE_PARM(iobase2, "i");
-MODULE_PARM(iobase3, "i");
+module_param(iobase, int, 0);
+module_param(iobase1, int, 0);
+module_param(iobase2, int, 0);
+module_param(iobase3, int, 0);
 
 MODULE_LICENSE("GPL");
 #endif /* MODULE */
index d58f823188539651f6e6eabd76ac091cae7f835b..35082dc12eaee8181cfd0344c15addcf82a4ed16 100644 (file)
 /* Whether we react on sysrq keys or just ignore them */
 int sysrq_enabled = 1;
 
-/* Loglevel sysrq handler */
 static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
-                                 struct tty_struct *tty) 
+                                 struct tty_struct *tty)
 {
        int i;
        i = key - '0';
        console_loglevel = 7;
        printk("Loglevel set to %d\n", i);
        console_loglevel = i;
-}      
+}
 static struct sysrq_key_op sysrq_loglevel_op = {
        .handler        = sysrq_handle_loglevel,
        .help_msg       = "loglevel0-8",
@@ -59,11 +58,9 @@ static struct sysrq_key_op sysrq_loglevel_op = {
        .enable_mask    = SYSRQ_ENABLE_LOG,
 };
 
-
-/* SAK sysrq handler */
 #ifdef CONFIG_VT
 static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
-                            struct tty_struct *tty) 
+                            struct tty_struct *tty)
 {
        if (tty)
                do_SAK(tty);
@@ -75,12 +72,13 @@ static struct sysrq_key_op sysrq_SAK_op = {
        .action_msg     = "SAK",
        .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
 };
+#else
+#define sysrq_SAK_op (*(struct sysrq_key_op *)0)
 #endif
 
 #ifdef CONFIG_VT
-/* unraw sysrq handler */
 static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
-                              struct tty_struct *tty) 
+                              struct tty_struct *tty)
 {
        struct kbd_struct *kbd = &kbd_table[fg_console];
 
@@ -93,10 +91,11 @@ static struct sysrq_key_op sysrq_unraw_op = {
        .action_msg     = "Keyboard mode set to XLATE",
        .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
 };
+#else
+#define sysrq_unraw_op (*(struct sysrq_key_op *)0)
 #endif /* CONFIG_VT */
 
 #ifdef CONFIG_KEXEC
-/* crashdump sysrq handler */
 static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
                                struct tty_struct *tty)
 {
@@ -108,16 +107,16 @@ static struct sysrq_key_op sysrq_crashdump_op = {
        .action_msg     = "Trigger a crashdump",
        .enable_mask    = SYSRQ_ENABLE_DUMP,
 };
+#else
+#define sysrq_crashdump_op (*(struct sysrq_key_op *)0)
 #endif
 
-/* reboot sysrq handler */
 static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
-                               struct tty_struct *tty) 
+                               struct tty_struct *tty)
 {
        local_irq_enable();
        emergency_restart();
 }
-
 static struct sysrq_key_op sysrq_reboot_op = {
        .handler        = sysrq_handle_reboot,
        .help_msg       = "reBoot",
@@ -126,11 +125,10 @@ static struct sysrq_key_op sysrq_reboot_op = {
 };
 
 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
-                             struct tty_struct *tty) 
+                             struct tty_struct *tty)
 {
        emergency_sync();
 }
-
 static struct sysrq_key_op sysrq_sync_op = {
        .handler        = sysrq_handle_sync,
        .help_msg       = "Sync",
@@ -139,11 +137,10 @@ static struct sysrq_key_op sysrq_sync_op = {
 };
 
 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
-                                struct tty_struct *tty) 
+                                struct tty_struct *tty)
 {
        emergency_remount();
 }
-
 static struct sysrq_key_op sysrq_mountro_op = {
        .handler        = sysrq_handle_mountro,
        .help_msg       = "Unmount",
@@ -151,28 +148,23 @@ static struct sysrq_key_op sysrq_mountro_op = {
        .enable_mask    = SYSRQ_ENABLE_REMOUNT,
 };
 
-/* END SYNC SYSRQ HANDLERS BLOCK */
-
 #ifdef CONFIG_DEBUG_MUTEXES
-
-static void
-sysrq_handle_showlocks(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs,
+                               struct tty_struct *tty)
 {
        mutex_debug_show_all_locks();
 }
-
 static struct sysrq_key_op sysrq_showlocks_op = {
        .handler        = sysrq_handle_showlocks,
        .help_msg       = "show-all-locks(D)",
        .action_msg     = "Show Locks Held",
 };
-
+#else
+#define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
 #endif
 
-/* SHOW SYSRQ HANDLERS BLOCK */
-
 static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
-                                 struct tty_struct *tty) 
+                                 struct tty_struct *tty)
 {
        if (pt_regs)
                show_regs(pt_regs);
@@ -184,9 +176,8 @@ static struct sysrq_key_op sysrq_showregs_op = {
        .enable_mask    = SYSRQ_ENABLE_DUMP,
 };
 
-
 static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
-                                  struct tty_struct *tty) 
+                                  struct tty_struct *tty)
 {
        show_state();
 }
@@ -197,9 +188,8 @@ static struct sysrq_key_op sysrq_showstate_op = {
        .enable_mask    = SYSRQ_ENABLE_DUMP,
 };
 
-
 static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
-                                struct tty_struct *tty) 
+                                struct tty_struct *tty)
 {
        show_mem();
 }
@@ -210,13 +200,9 @@ static struct sysrq_key_op sysrq_showmem_op = {
        .enable_mask    = SYSRQ_ENABLE_DUMP,
 };
 
-/* SHOW SYSRQ HANDLERS BLOCK */
-
-
-/* SIGNAL SYSRQ HANDLERS BLOCK */
-
-/* signal sysrq helper function
- * Sends a signal to all user processes */
+/*
+ * Signal sysrq helper function.  Sends a signal to all user processes.
+ */
 static void send_sig_all(int sig)
 {
        struct task_struct *p;
@@ -229,7 +215,7 @@ static void send_sig_all(int sig)
 }
 
 static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
-                             struct tty_struct *tty) 
+                             struct tty_struct *tty)
 {
        send_sig_all(SIGTERM);
        console_loglevel = 8;
@@ -243,7 +229,8 @@ static struct sysrq_key_op sysrq_term_op = {
 
 static void moom_callback(void *ignored)
 {
-       out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0);
+       out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL],
+                       GFP_KERNEL, 0);
 }
 
 static DECLARE_WORK(moom_work, moom_callback, NULL);
@@ -260,7 +247,7 @@ static struct sysrq_key_op sysrq_moom_op = {
 };
 
 static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
-                             struct tty_struct *tty) 
+                             struct tty_struct *tty)
 {
        send_sig_all(SIGKILL);
        console_loglevel = 8;
@@ -272,8 +259,6 @@ static struct sysrq_key_op sysrq_kill_op = {
        .enable_mask    = SYSRQ_ENABLE_SIGNAL,
 };
 
-/* END SIGNAL SYSRQ HANDLERS BLOCK */
-
 static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs,
                                struct tty_struct *tty)
 {
@@ -288,110 +273,99 @@ static struct sysrq_key_op sysrq_unrt_op = {
 
 /* Key Operations table and lock */
 static DEFINE_SPINLOCK(sysrq_key_table_lock);
-#define SYSRQ_KEY_TABLE_LENGTH 36
-static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
-/* 0 */        &sysrq_loglevel_op,
-/* 1 */        &sysrq_loglevel_op,
-/* 2 */        &sysrq_loglevel_op,
-/* 3 */        &sysrq_loglevel_op,
-/* 4 */        &sysrq_loglevel_op,
-/* 5 */        &sysrq_loglevel_op,
-/* 6 */        &sysrq_loglevel_op,
-/* 7 */        &sysrq_loglevel_op,
-/* 8 */        &sysrq_loglevel_op,
-/* 9 */        &sysrq_loglevel_op,
-/* a */        NULL, /* Don't use for system provided sysrqs,
-                it is handled specially on the sparc
-                and will never arrive */
-/* b */        &sysrq_reboot_op,
-#ifdef CONFIG_KEXEC
-/* c */ &sysrq_crashdump_op,
-#else
-/* c */        NULL,
-#endif
-#ifdef CONFIG_DEBUG_MUTEXES
-/* d */ &sysrq_showlocks_op,
-#else
-/* d */ NULL,
-#endif
-/* e */        &sysrq_term_op,
-/* f */        &sysrq_moom_op,
-/* g */        NULL,
-/* h */        NULL,
-/* i */        &sysrq_kill_op,
-/* j */        NULL,
-#ifdef CONFIG_VT
-/* k */        &sysrq_SAK_op,
-#else
-/* k */        NULL,
-#endif
-/* l */        NULL,
-/* m */        &sysrq_showmem_op,
-/* n */        &sysrq_unrt_op,
-/* o */        NULL, /* This will often be registered
-                as 'Off' at init time */
-/* p */        &sysrq_showregs_op,
-/* q */        NULL,
-#ifdef CONFIG_VT
-/* r */        &sysrq_unraw_op,
-#else
-/* r */ NULL,
-#endif
-/* s */        &sysrq_sync_op,
-/* t */        &sysrq_showstate_op,
-/* u */        &sysrq_mountro_op,
-/* v */        NULL, /* May be assigned at init time by SMP VOYAGER */
-/* w */        NULL,
-/* x */        NULL,
-/* y */        NULL,
-/* z */        NULL
+
+static struct sysrq_key_op *sysrq_key_table[36] = {
+       &sysrq_loglevel_op,             /* 0 */
+       &sysrq_loglevel_op,             /* 1 */
+       &sysrq_loglevel_op,             /* 2 */
+       &sysrq_loglevel_op,             /* 3 */
+       &sysrq_loglevel_op,             /* 4 */
+       &sysrq_loglevel_op,             /* 5 */
+       &sysrq_loglevel_op,             /* 6 */
+       &sysrq_loglevel_op,             /* 7 */
+       &sysrq_loglevel_op,             /* 8 */
+       &sysrq_loglevel_op,             /* 9 */
+
+       /*
+        * Don't use for system provided sysrqs, it is handled specially on
+        * sparc and will never arrive
+        */
+       NULL,                           /* a */
+       &sysrq_reboot_op,               /* b */
+       &sysrq_crashdump_op,            /* c */
+       &sysrq_showlocks_op,            /* d */
+       &sysrq_term_op,                 /* e */
+       &sysrq_moom_op,                 /* f */
+       NULL,                           /* g */
+       NULL,                           /* h */
+       &sysrq_kill_op,                 /* i */
+       NULL,                           /* j */
+       &sysrq_SAK_op,                  /* k */
+       NULL,                           /* l */
+       &sysrq_showmem_op,              /* m */
+       &sysrq_unrt_op,                 /* n */
+       /* This will often be registered as 'Off' at init time */
+       NULL,                           /* o */
+       &sysrq_showregs_op,             /* p */
+       NULL,                           /* q */
+       &sysrq_unraw_op,                        /* r */
+       &sysrq_sync_op,                 /* s */
+       &sysrq_showstate_op,            /* t */
+       &sysrq_mountro_op,              /* u */
+       /* May be assigned at init time by SMP VOYAGER */
+       NULL,                           /* v */
+       NULL,                           /* w */
+       NULL,                           /* x */
+       NULL,                           /* y */
+       NULL                            /* z */
 };
 
 /* key2index calculation, -1 on invalid index */
-static int sysrq_key_table_key2index(int key) {
+static int sysrq_key_table_key2index(int key)
+{
        int retval;
-       if ((key >= '0') && (key <= '9')) {
+
+       if ((key >= '0') && (key <= '9'))
                retval = key - '0';
-       } else if ((key >= 'a') && (key <= 'z')) {
+       else if ((key >= 'a') && (key <= 'z'))
                retval = key + 10 - 'a';
-       } else {
+       else
                retval = -1;
-       }
        return retval;
 }
 
 /*
  * get and put functions for the table, exposed to modules.
  */
-
-struct sysrq_key_op *__sysrq_get_key_op (int key) {
-        struct sysrq_key_op *op_p;
+struct sysrq_key_op *__sysrq_get_key_op(int key)
+{
+        struct sysrq_key_op *op_p = NULL;
         int i;
-       
+
        i = sysrq_key_table_key2index(key);
-        op_p = (i == -1) ? NULL : sysrq_key_table[i];
+       if (i != -1)
+               op_p = sysrq_key_table[i];
         return op_p;
 }
 
-static void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
-        int i;
+static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
+{
+        int i = sysrq_key_table_key2index(key);
 
-       i = sysrq_key_table_key2index(key);
         if (i != -1)
                 sysrq_key_table[i] = op_p;
 }
 
 /*
- * This is the non-locking version of handle_sysrq
- * It must/can only be called by sysrq key handlers,
- * as they are inside of the lock
+ * This is the non-locking version of handle_sysrq.  It must/can only be called
+ * by sysrq key handlers, as they are inside of the lock
  */
-
-void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, int check_mask)
+void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
+                       int check_mask)
 {
        struct sysrq_key_op *op_p;
        int orig_log_level;
-       int i, j;
+       int i;
        unsigned long flags;
 
        spin_lock_irqsave(&sysrq_key_table_lock, flags);
@@ -401,26 +375,34 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, in
 
         op_p = __sysrq_get_key_op(key);
         if (op_p) {
-               /* Should we check for enabled operations (/proc/sysrq-trigger should not)
-                * and is the invoked operation enabled? */
+               /*
+                * Should we check for enabled operations (/proc/sysrq-trigger
+                * should not) and is the invoked operation enabled?
+                */
                if (!check_mask || sysrq_enabled == 1 ||
                    (sysrq_enabled & op_p->enable_mask)) {
-                       printk ("%s\n", op_p->action_msg);
+                       printk("%s\n", op_p->action_msg);
                        console_loglevel = orig_log_level;
                        op_p->handler(key, pt_regs, tty);
-               }
-               else
+               } else {
                        printk("This sysrq operation is disabled.\n");
+               }
        } else {
                printk("HELP : ");
                /* Only print the help msg once per handler */
-               for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) 
-               if (sysrq_key_table[i]) {
-                       for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
-                       if (j == i)
-                               printk ("%s ", sysrq_key_table[i]->help_msg);
+               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
+                       if (sysrq_key_table[i]) {
+                               int j;
+
+                               for (j = 0; sysrq_key_table[i] !=
+                                               sysrq_key_table[j]; j++)
+                                       ;
+                               if (j != i)
+                                       continue;
+                               printk("%s ", sysrq_key_table[i]->help_msg);
+                       }
                }
-               printk ("\n");
+               printk("\n");
                console_loglevel = orig_log_level;
        }
        spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
@@ -430,16 +412,17 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty, in
  * This function is called by the keyboard handler when SysRq is pressed
  * and any other keycode arrives.
  */
-
 void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
 {
        if (!sysrq_enabled)
                return;
        __handle_sysrq(key, pt_regs, tty, 1);
 }
+EXPORT_SYMBOL(handle_sysrq);
 
 static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
-                                struct sysrq_key_op *remove_op_p) {
+                                struct sysrq_key_op *remove_op_p)
+{
 
        int retval;
        unsigned long flags;
@@ -452,7 +435,6 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
                retval = -1;
        }
        spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-
        return retval;
 }
 
@@ -460,12 +442,10 @@ int register_sysrq_key(int key, struct sysrq_key_op *op_p)
 {
        return __sysrq_swap_key_ops(key, op_p, NULL);
 }
+EXPORT_SYMBOL(register_sysrq_key);
 
 int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
 {
        return __sysrq_swap_key_ops(key, NULL, op_p);
 }
-
-EXPORT_SYMBOL(handle_sysrq);
-EXPORT_SYMBOL(register_sysrq_key);
 EXPORT_SYMBOL(unregister_sysrq_key);
index fd3a4beaa53d941adcc4d0bfab0932354fa0b8d2..dec0224b4478803c566cb932ae81da22d1d00bed 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 enum tpm_timeout {
        TPM_TIMEOUT = 5,        /* msecs */
index 76592ee1fb38d6813831d98ef5de613dd7f2516b..48d795bb8c4b7a33ec4d4a3bd81ea3537aa6cec9 100644 (file)
@@ -354,7 +354,7 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
 
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
-int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size)
+int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size)
 {
        int copied = 0;
        do {
@@ -378,7 +378,7 @@ int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t
 
 EXPORT_SYMBOL_GPL(tty_insert_flip_string);
 
-int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size)
+int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size)
 {
        int copied = 0;
        do {
index c0dfcf273f0a5bd84e3be9dcd4f4a22835dcd198..16e99db2e12d6b532aa152aa811c6f9567fde69f 100644 (file)
@@ -148,6 +148,16 @@ config MPCORE_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called mpcore_wdt.
 
+config EP93XX_WATCHDOG
+       tristate "EP93xx Watchdog"
+       depends on WATCHDOG && ARCH_EP93XX
+       help
+         Say Y here if to include support for the watchdog timer
+         embedded in the Cirrus Logic EP93xx family of devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ep93xx_wdt.
+
 # X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
index 36c0b282b8ba30d3119325acd5fb844a65d1aa7f..d6f27fde9905663a5cd0c21c1c32a62aa7044ec0 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
+obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
new file mode 100644 (file)
index 0000000..9021dbb
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Watchdog driver for Cirrus Logic EP93xx family of devices.
+ *
+ * Copyright (c) 2004 Ray Lehtiniemi
+ * Copyright (c) 2006 Tower Technologies
+ * Based on ep93xx driver, bits from alim7101_wdt.c
+ *
+ * Authors: Ray Lehtiniemi <rayl@mail.com>,
+ *     Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * This watchdog fires after 250msec, which is a too short interval
+ * for us to rely on the user space daemon alone. So we ping the
+ * wdt each ~200msec and eventually stop doing it if the user space
+ * daemon dies.
+ *
+ * TODO:
+ *
+ *     - Test last reset from watchdog status
+ *     - Add a few missing ioctls
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/timer.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+
+#define WDT_VERSION    "0.3"
+#define PFX            "ep93xx_wdt: "
+
+/* default timeout (secs) */
+#define WDT_TIMEOUT 30
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int timeout = WDT_TIMEOUT;
+
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_IN_USE             0
+#define WDT_OK_TO_CLOSE                1
+
+#define EP93XX_WDT_REG(x)      (EP93XX_WATCHDOG_BASE + (x))
+#define EP93XX_WDT_WATCHDOG    EP93XX_WDT_REG(0x00)
+#define EP93XX_WDT_WDSTATUS    EP93XX_WDT_REG(0x04)
+
+/* reset the wdt every ~200ms */
+#define WDT_INTERVAL (HZ/5)
+
+static void wdt_enable(void)
+{
+       __raw_writew(0xaaaa, EP93XX_WDT_WATCHDOG);
+}
+
+static void wdt_disable(void)
+{
+       __raw_writew(0xaa55, EP93XX_WDT_WATCHDOG);
+}
+
+static inline void wdt_ping(void)
+{
+       __raw_writew(0x5555, EP93XX_WDT_WATCHDOG);
+}
+
+static void wdt_startup(void)
+{
+       next_heartbeat = jiffies + (timeout * HZ);
+
+       wdt_enable();
+       mod_timer(&timer, jiffies + WDT_INTERVAL);
+}
+
+static void wdt_shutdown(void)
+{
+       del_timer_sync(&timer);
+       wdt_disable();
+}
+
+static void wdt_keepalive(void)
+{
+       /* user land ping */
+       next_heartbeat = jiffies + (timeout * HZ);
+}
+
+static int ep93xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       wdt_startup();
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t
+ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
+                loff_t *ppos)
+{
+       /* Can't seek (pwrite) on this device */
+       if (*ppos != file->f_pos)
+               return -ESPIPE;
+
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                               else
+                                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_keepalive();
+       }
+
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
+       .identity = "EP93xx Watchdog",
+};
+
+static int
+ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                unsigned long arg)
+{
+       int ret = -ENOIOCTLCMD;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
+                               sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int __user *)arg);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(boot_status, (int __user *)arg);
+               break;
+
+       case WDIOC_GETTIMEOUT:
+               /* actually, it is 0.250 seconds.... */
+               ret = put_user(1, (int __user *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_keepalive();
+               ret = 0;
+               break;
+       }
+       return ret;
+}
+
+static int ep93xx_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               wdt_shutdown();
+       else
+               printk(KERN_CRIT PFX "Device closed unexpectedly - "
+                       "timer will not stop\n");
+
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+static struct file_operations ep93xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .write          = ep93xx_wdt_write,
+       .ioctl          = ep93xx_wdt_ioctl,
+       .open           = ep93xx_wdt_open,
+       .release        = ep93xx_wdt_release,
+};
+
+static struct miscdevice ep93xx_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &ep93xx_wdt_fops,
+};
+
+static void ep93xx_timer_ping(unsigned long data)
+{
+       if (time_before(jiffies, next_heartbeat))
+               wdt_ping();
+
+       /* Re-set the timer interval */
+       mod_timer(&timer, jiffies + WDT_INTERVAL);
+}
+
+static int __init ep93xx_wdt_init(void)
+{
+       int err;
+
+       err = misc_register(&ep93xx_wdt_miscdev);
+
+       boot_status = __raw_readl(EP93XX_WDT_WATCHDOG) & 0x01 ? 1 : 0;
+
+       printk(KERN_INFO PFX "EP93XX watchdog, driver version "
+               WDT_VERSION "%s\n",
+               (__raw_readl(EP93XX_WDT_WATCHDOG) & 0x08)
+               ? " (nCS1 disable detected)" : "");
+
+       if (timeout < 1 || timeout > 3600) {
+               timeout = WDT_TIMEOUT;
+               printk(KERN_INFO PFX
+                       "timeout value must be 1<=x<=3600, using %d\n",
+                       timeout);
+       }
+
+       setup_timer(&timer, ep93xx_timer_ping, 1);
+       return err;
+}
+
+static void __exit ep93xx_wdt_exit(void)
+{
+       wdt_shutdown();
+       misc_deregister(&ep93xx_wdt_miscdev);
+}
+
+module_init(ep93xx_wdt_init);
+module_exit(ep93xx_wdt_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
+               "Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("EP93xx Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(WDT_VERSION);
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index ca8e69d2f64d632118c32e9c05c63a5ae660a71e..e4c48e329367d93617635e65a671ffb2816a47f7 100644 (file)
@@ -71,22 +71,17 @@ static int dio_device_probe(struct device *dev)
         *  @drv: the driver structure to register
         *
         *  Adds the driver structure to the list of registered drivers
-        *  Returns the number of DIO devices which were claimed by the driver
-        *  during registration.  The driver remains registered even if the
-        *  return value is zero.
+        *  Returns zero or a negative error value.
         */
 
 int dio_register_driver(struct dio_driver *drv)
 {
-       int count = 0;
-
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &dio_bus_type;
 
        /* register with core */
-       count = driver_register(&drv->driver);
-       return count ? count : 1;
+       return driver_register(&drv->driver);
 }
 
 
diff --git a/drivers/eisa/.gitignore b/drivers/eisa/.gitignore
new file mode 100644 (file)
index 0000000..4b335c0
--- /dev/null
@@ -0,0 +1 @@
+devlist.h
index 4196137e66dea5b9e191b86b6988766985a040ba..6078e2f588172e73aad9ad45ec2a3cfb9eb7e97d 100644 (file)
@@ -135,13 +135,8 @@ struct bus_type eisa_bus_type = {
 
 int eisa_driver_register (struct eisa_driver *edrv)
 {
-       int r;
-       
        edrv->driver.bus = &eisa_bus_type;
-       if ((r = driver_register (&edrv->driver)) < 0)
-               return r;
-
-       return 0;
+       return driver_register (&edrv->driver);
 }
 
 void eisa_driver_unregister (struct eisa_driver *edrv)
index b2cc43702f65ab5738e533c4152ba3aa9f90f3e7..3fdab563fec25f405a7903b8c13002206d47d45e 100644 (file)
@@ -2058,7 +2058,7 @@ static void __init parse_options (char *line)
        }
 }
 
-int init_module (void)
+int __init init_module (void)
 {
        parse_options(options);
        return ide_init();
index 8c12a974b411a75093c2f65319b4c88761bc5dd7..a81f987978c8712a826fabb15f398e963876fe8e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/interrupt.h>
 
 #ifdef CONFIG_ARM
 #include <asm/mach-types.h>
index 91dd0551fc7ceacc3e83fe09cdae5dcb9ba867b6..4d64e5cbcdbf84e4d897aa5f48e201026cf1df5e 100644 (file)
@@ -39,7 +39,7 @@ MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
 
 static int suppress_pollack = 0;
-MODULE_PARM(suppress_pollack, "0-1i");
+module_param(suppress_pollack, bool, 0);
 
 /* ------------------------------------------------------------- */
 
index 38bd4dfecbd168c6009176f526bfed69c60f39cd..80fb488848b81ac2cc64e6613e80c21001e5b223 100644 (file)
@@ -169,8 +169,8 @@ static struct pci_dev isa_dev[MAX_CARDS];
 static int io[MAX_CARDS];
 static int irq[MAX_CARDS];
 
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 
index 724aac2c1ccaf1669de1fb73f04b087d20959d03..f7253b2136ea969b8ff3e88171db35bf7035073d 100644 (file)
@@ -50,7 +50,7 @@ MODULE_DEVICE_TABLE(pci, c4_pci_tbl);
 MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
-MODULE_PARM(suppress_pollack, "0-1i");
+module_param(suppress_pollack, bool, 0);
 
 /* ------------------------------------------------------------- */
 
index 3b701d97bdf1e150b281badea07301aa57ba323e..5a2f854d55b5c8317de59f09c10e864a12ac9af5 100644 (file)
@@ -519,9 +519,9 @@ static int io[MAX_CARDS];
 static int irq[MAX_CARDS];
 static int cardnr[MAX_CARDS];
 
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
-MODULE_PARM(cardnr, "1-" __MODULE_STRING(MAX_CARDS) "i");
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(cardnr, int, NULL, 0);
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)");
index e19a01a305a9f2a7d4800cc51247f63e314e0a79..48d134be99088166e9f711e8f6160932f49fa8f4 100644 (file)
@@ -38,8 +38,8 @@ ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
        hysdn_card *card = dev_id;      /* parameter from irq */
        tErgDpram *dpr;
-       ulong flags;
-       uchar volatile b;
+       unsigned long flags;
+       unsigned char volatile b;
 
        if (!card)
                return IRQ_NONE;                /* error -> spurious interrupt */
@@ -77,7 +77,7 @@ ergo_irq_bh(hysdn_card * card)
 {
        tErgDpram *dpr;
        int again;
-       ulong flags;
+       unsigned long flags;
 
        if (card->state != CARD_STATE_RUN)
                return;         /* invalid call */
@@ -131,8 +131,8 @@ ergo_irq_bh(hysdn_card * card)
 static void
 ergo_stopcard(hysdn_card * card)
 {
-       ulong flags;
-       uchar val;
+       unsigned long flags;
+       unsigned char val;
 
        hysdn_net_release(card);        /* first release the net device if existing */
 #ifdef CONFIG_HYSDN_CAPI
@@ -157,7 +157,7 @@ ergo_stopcard(hysdn_card * card)
 static void
 ergo_set_errlog_state(hysdn_card * card, int on)
 {
-       ulong flags;
+       unsigned long flags;
 
        if (card->state != CARD_STATE_RUN) {
                card->err_log_state = ERRLOG_STATE_OFF;         /* must be off */
@@ -217,9 +217,10 @@ ergo_testram(hysdn_card * card)
 /* Negative return values are interpreted as errors.                         */
 /*****************************************************************************/
 static int
-ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
+ergo_writebootimg(struct HYSDN_CARD *card, unsigned char *buf,
+                       unsigned long offs)
 {
-       uchar *dst;
+       unsigned char *dst;
        tErgDpram *dpram;
        int cnt = (BOOT_IMG_SIZE >> 2);         /* number of words to move and swap (byte order!) */
        
@@ -264,14 +265,14 @@ ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
 /* case of errors a negative error value is returned.                           */
 /********************************************************************************/
 static int
-ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
+ergo_writebootseq(struct HYSDN_CARD *card, unsigned char *buf, int len)
 {
        tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
-       uchar *dst;
-       uchar buflen;
+       unsigned char *dst;
+       unsigned char buflen;
        int nr_write;
-       uchar tmp_rdptr;
-       uchar wr_mirror;
+       unsigned char tmp_rdptr;
+       unsigned char wr_mirror;
        int i;
 
        if (card->debug_flags & LOG_POF_CARD)
@@ -330,7 +331,7 @@ ergo_waitpofready(struct HYSDN_CARD *card)
 {
        tErgDpram *dpr = card->dpram;   /* pointer to DPRAM structure */
        int timecnt = 10000 / 50;       /* timeout is 10 secs max. */
-       ulong flags;
+       unsigned long flags;
        int msg_size;
        int i;
 
@@ -345,7 +346,7 @@ ergo_waitpofready(struct HYSDN_CARD *card)
                        if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
                            (dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
                            (dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
-                           ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
+                           ((*(unsigned long *) dpr->ToPcBuf) != RDY_MAGIC))
                                break;  /* an error occurred */
 
                        /* Check for additional data delivered during SysReady */
index b56ff0889ead52a9f37d02895eec9dddce2a4f29..c59422aa8c3fbd6b4adb2e034b44962c2ff07954 100644 (file)
 
 /* following DPRAM layout copied from OS2-driver boarderg.h */
 typedef struct ErgDpram_tag {
-/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
-/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
+/*0000 */ unsigned char ToHyBuf[ERG_TO_HY_BUF_SIZE];
+/*0E00 */ unsigned char ToPcBuf[ERG_TO_PC_BUF_SIZE];
 
-       /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
+       /*1C00 */ unsigned char bSoftUart[SIZE_RSV_SOFT_UART];
        /* size 0x1B0 */
 
-       /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
+       /*1DB0 *//* tErrLogEntry */ unsigned char volatile ErrLogMsg[64];
        /* size 64 bytes */
-       /*1DB0  ulong ulErrType;               */
-       /*1DB4  ulong ulErrSubtype;            */
-       /*1DB8  ulong ucTextSize;              */
-       /*1DB9  ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
+       /*1DB0  unsigned long ulErrType;               */
+       /*1DB4  unsigned long ulErrSubtype;            */
+       /*1DB8  unsigned long ucTextSize;              */
+       /*1DB9  unsigned long ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
        /*1DF0 */
 
-/*1DF0 */ word volatile ToHyChannel;
-/*1DF2 */ word volatile ToHySize;
-       /*1DF4 */ uchar volatile ToHyFlag;
+/*1DF0 */ unsigned short volatile ToHyChannel;
+/*1DF2 */ unsigned short volatile ToHySize;
+       /*1DF4 */ unsigned char volatile ToHyFlag;
        /* !=0: msg for Hy waiting */
-       /*1DF5 */ uchar volatile ToPcFlag;
+       /*1DF5 */ unsigned char volatile ToPcFlag;
        /* !=0: msg for PC waiting */
-/*1DF6 */ word volatile ToPcChannel;
-/*1DF8 */ word volatile ToPcSize;
-       /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
+/*1DF6 */ unsigned short volatile ToPcChannel;
+/*1DF8 */ unsigned short volatile ToPcSize;
+       /*1DFA */ unsigned char bRes1DBA[0x1E00 - 0x1DFA];
        /* 6 bytes */
 
-/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
-/*1F00 */ ulong TrapTable[62];
-       /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
+/*1E00 */ unsigned char bRestOfEntryTbl[0x1F00 - 0x1E00];
+/*1F00 */ unsigned long TrapTable[62];
+       /*1FF8 */ unsigned char bRes1FF8[0x1FFB - 0x1FF8];
        /* low part of reset vetor */
-/*1FFB */ uchar ToPcIntMetro;
+/*1FFB */ unsigned char ToPcIntMetro;
        /* notes:
         * - metro has 32-bit boot ram - accessing
         *   ToPcInt and ToHyInt would be the same;
@@ -65,16 +65,16 @@ typedef struct ErgDpram_tag {
         *   so E1 side should NOT change this byte
         *   when writing!
         */
-/*1FFC */ uchar volatile ToHyNoDpramErrLog;
+/*1FFC */ unsigned char volatile ToHyNoDpramErrLog;
        /* note: ToHyNoDpramErrLog is used to inform
         *       boot loader, not to use DPRAM based
         *       ErrLog; when DOS driver is rewritten
         *       this becomes obsolete
         */
-/*1FFD */ uchar bRes1FFD;
-       /*1FFE */ uchar ToPcInt;
+/*1FFD */ unsigned char bRes1FFD;
+       /*1FFE */ unsigned char ToPcInt;
        /* E1_intclear; on CHAMP2: E1_intset   */
-       /*1FFF */ uchar ToHyInt;
+       /*1FFF */ unsigned char ToHyInt;
        /* E1_intset;   on CHAMP2: E1_intclear */
 } tErgDpram;
 
index acc1d3cceebb35214018fd34fd898cd0518824bb..6bac43cc91bdb2b9284c6613c9a35a3cf96acb63 100644 (file)
@@ -31,7 +31,7 @@
 static char hycapi_revision[]="$Revision: 1.8.6.4 $";
 
 unsigned int hycapi_enable = 0xffffffff; 
-MODULE_PARM(hycapi_enable, "i");
+module_param(hycapi_enable, uint, 0);
 
 typedef struct _hycapi_appl {
        unsigned int ctrl_mask;
@@ -523,7 +523,7 @@ New nccis are created if necessary.
 *******************************************************************/
 
 void
-hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len)
+hycapi_rx_capipkt(hysdn_card * card, unsigned char *buf, unsigned short len)
 {
        struct sk_buff *skb;
        hycapictrl_info *cinfo = card->hyctrlinfo;
index 7bfba196f3155a9db17137fcab48e5195f3e9bdc..6d0eb0f42fcacce1048231e25dee4ba59a763ca6 100644 (file)
 /* needed during boot and so allocated dynamically.         */
 /************************************************************/
 struct boot_data {
-       word Cryptor;           /* for use with Decrypt function */
-       word Nrecs;             /* records remaining in file */
-       uchar pof_state;        /* actual state of read handler */
-       uchar is_crypted;       /* card data is crypted */
+       unsigned short Cryptor; /* for use with Decrypt function */
+       unsigned short Nrecs;   /* records remaining in file */
+       unsigned char pof_state;/* actual state of read handler */
+       unsigned char is_crypted;/* card data is crypted */
        int BufSize;            /* actual number of bytes bufferd */
        int last_error;         /* last occurred error */
-       word pof_recid;         /* actual pof recid */
-       ulong pof_reclen;       /* total length of pof record data */
-       ulong pof_recoffset;    /* actual offset inside pof record */
+       unsigned short pof_recid;/* actual pof recid */
+       unsigned long pof_reclen;/* total length of pof record data */
+       unsigned long pof_recoffset;/* actual offset inside pof record */
        union {
-               uchar BootBuf[BOOT_BUF_SIZE];   /* buffer as byte count */
+               unsigned char BootBuf[BOOT_BUF_SIZE];/* buffer as byte count */
                tPofRecHdr PofRecHdr;   /* header for actual record/chunk */
                tPofFileHdr PofFileHdr;         /* header from POF file */
                tPofTimeStamp PofTime;  /* time information */
@@ -69,11 +69,11 @@ StartDecryption(struct boot_data *boot)
 static void
 DecryptBuf(struct boot_data *boot, int cnt)
 {
-       uchar *bufp = boot->buf.BootBuf;
+       unsigned char *bufp = boot->buf.BootBuf;
 
        while (cnt--) {
                boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
-               *bufp++ ^= (uchar) boot->Cryptor;
+               *bufp++ ^= (unsigned char)boot->Cryptor;
        }
 }                              /* DecryptBuf */
 
@@ -86,7 +86,7 @@ pof_handle_data(hysdn_card * card, int datlen)
 {
        struct boot_data *boot = card->boot;    /* pointer to boot specific data */
        long l;
-       uchar *imgp;
+       unsigned char *imgp;
        int img_len;
 
        /* handle the different record types */
@@ -197,7 +197,7 @@ pof_write_buffer(hysdn_card * card, int datlen)
                                break;
                        }
                        /* Setup the new state and vars */
-                       boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs);  /* limited to 65535 */
+                       boot->Nrecs = (unsigned short)(boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
                        boot->pof_state = POF_READ_TAG_HEAD;    /* now start with single tags */
                        boot->last_error = sizeof(tPofRecHdr);  /* new length */
                        break;
@@ -268,7 +268,7 @@ pof_write_buffer(hysdn_card * card, int datlen)
 /* occurred. Additionally the pointer to the buffer data area is set on success */
 /*******************************************************************************/
 int
-pof_write_open(hysdn_card * card, uchar ** bufp)
+pof_write_open(hysdn_card * card, unsigned char **bufp)
 {
        struct boot_data *boot; /* pointer to boot specific data */
 
@@ -335,7 +335,7 @@ pof_write_close(hysdn_card * card)
 /* when POF has been booted. A return value of 0 is used if no error occurred.    */
 /*********************************************************************************/
 int
-EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
+EvalSysrTokData(hysdn_card *card, unsigned char *cp, int len)
 {
        u_char *p;
        u_char crc;
index 432f6f99089e5dd5109bcb6b828a8336301eeaf1..3a9b29b38bc4eef1afeebab6f8d42a38846c57a2 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/skbuff.h>
 
-/****************************/
-/* storage type definitions */
-/****************************/
-#define uchar unsigned char
-#define uint unsigned int
-#define ulong unsigned long
-#define word unsigned short
-
 #include "ince1pc.h"
 
 #ifdef CONFIG_HYSDN_CAPI
@@ -147,18 +139,18 @@ typedef struct HYSDN_CARD {
 
        /* general variables for the cards */
        int myid;               /* own driver card id */
-       uchar bus;              /* pci bus the card is connected to */
-       uchar devfn;            /* slot+function bit encoded */
-       word subsysid;          /* PCI subsystem id */
-       uchar brdtype;          /* type of card */
-       uint bchans;            /* number of available B-channels */
-       uint faxchans;          /* number of available fax-channels */
-       uchar mac_addr[6];      /* MAC Address read from card */
-       uint irq;               /* interrupt number */
-       uint iobase;            /* IO-port base address */
-       ulong plxbase;          /* PLX memory base */
-       ulong membase;          /* DPRAM memory base */
-       ulong memend;           /* DPRAM memory end */
+       unsigned char bus;      /* pci bus the card is connected to */
+       unsigned char devfn;    /* slot+function bit encoded */
+       unsigned short subsysid;/* PCI subsystem id */
+       unsigned char brdtype;  /* type of card */
+       unsigned int bchans;    /* number of available B-channels */
+       unsigned int faxchans;  /* number of available fax-channels */
+       unsigned char mac_addr[6];/* MAC Address read from card */
+       unsigned int irq;       /* interrupt number */
+       unsigned int iobase;    /* IO-port base address */
+       unsigned long plxbase;  /* PLX memory base */
+       unsigned long membase;  /* DPRAM memory base */
+       unsigned long memend;   /* DPRAM memory end */
        void *dpram;            /* mapped dpram */
        int state;              /* actual state of card -> CARD_STATE_** */
        struct HYSDN_CARD *next;        /* pointer to next card */
@@ -168,26 +160,26 @@ typedef struct HYSDN_CARD {
        void *procconf;         /* pointer to procconf filesystem specific data */
 
        /* debugging and logging */
-       uchar err_log_state;    /* actual error log state of the card */
-       ulong debug_flags;      /* tells what should be debugged and where */
+       unsigned char err_log_state;/* actual error log state of the card */
+       unsigned long debug_flags;/* tells what should be debugged and where */
        void (*set_errlog_state) (struct HYSDN_CARD *, int);
 
        /* interrupt handler + interrupt synchronisation */
        struct work_struct irq_queue;   /* interrupt task queue */
-       uchar volatile irq_enabled;     /* interrupt enabled if != 0 */
-       uchar volatile hw_lock; /* hardware is currently locked -> no access */
+       unsigned char volatile irq_enabled;/* interrupt enabled if != 0 */
+       unsigned char volatile hw_lock;/* hardware is currently locked -> no access */
 
        /* boot process */
        void *boot;             /* pointer to boot private data */
-       int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
-       int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
+       int (*writebootimg) (struct HYSDN_CARD *, unsigned char *, unsigned long);
+       int (*writebootseq) (struct HYSDN_CARD *, unsigned char *, int);
        int (*waitpofready) (struct HYSDN_CARD *);
        int (*testram) (struct HYSDN_CARD *);
 
        /* scheduler for data transfer (only async parts) */
-       uchar async_data[256];  /* async data to be sent (normally for config) */
-       word volatile async_len;        /* length of data to sent */
-       word volatile async_channel;    /* channel number for async transfer */
+       unsigned char async_data[256];/* async data to be sent (normally for config) */
+       unsigned short volatile async_len;/* length of data to sent */
+       unsigned short volatile async_channel;/* channel number for async transfer */
        int volatile async_busy;        /* flag != 0 sending in progress */
        int volatile net_tx_busy;       /* a network packet tx is in progress */
 
@@ -251,15 +243,18 @@ extern int ergo_inithardware(hysdn_card * card);  /* get hardware -> module init
 
 /* hysdn_boot.c */
 extern int pof_write_close(hysdn_card *);      /* close proc file after writing pof */
-extern int pof_write_open(hysdn_card *, uchar **);     /* open proc file for writing pof */
+extern int pof_write_open(hysdn_card *, unsigned char **);     /* open proc file for writing pof */
 extern int pof_write_buffer(hysdn_card *, int);                /* write boot data to card */
-extern int EvalSysrTokData(hysdn_card *, uchar *, int);                /* Check Sysready Token Data */
+extern int EvalSysrTokData(hysdn_card *, unsigned char *, int);                /* Check Sysready Token Data */
 
 /* hysdn_sched.c */
-extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
-                         word);
-extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
-extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word);      /* send one cfg line */
+extern int hysdn_sched_tx(hysdn_card *, unsigned char *,
+                       unsigned short volatile *, unsigned short volatile *,
+                       unsigned short);
+extern int hysdn_sched_rx(hysdn_card *, unsigned char *, unsigned short,
+                       unsigned short);
+extern int hysdn_tx_cfgline(hysdn_card *, unsigned char *,
+                       unsigned short);        /* send one cfg line */
 
 /* hysdn_net.c */
 extern unsigned int hynet_enable; 
@@ -269,14 +264,16 @@ extern int hysdn_net_release(hysdn_card *);       /* delete the device */
 extern char *hysdn_net_getname(hysdn_card *);  /* get name of net interface */
 extern void hysdn_tx_netack(hysdn_card *);     /* acknowledge a packet tx */
 extern struct sk_buff *hysdn_tx_netget(hysdn_card *);  /* get next network packet */
-extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word);      /* rxed packet from network */
+extern void hysdn_rx_netpkt(hysdn_card *, unsigned char *,
+                       unsigned short);        /* rxed packet from network */
 
 #ifdef CONFIG_HYSDN_CAPI
 extern unsigned int hycapi_enable; 
 extern int hycapi_capi_create(hysdn_card *);   /* create a new capi device */
 extern int hycapi_capi_release(hysdn_card *);  /* delete the device */
 extern int hycapi_capi_stop(hysdn_card *card);   /* suspend */
-extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len);
+extern void hycapi_rx_capipkt(hysdn_card * card, unsigned char * buf,
+                               unsigned short len);
 extern void hycapi_tx_capiack(hysdn_card * card);
 extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card);
 extern int hycapi_init(void);
index cb791f8e793ae6335308a8afeeb164c42ebc546d..b75ac5af236a1a5eb102f1ff84554b2d23b02d28 100644 (file)
@@ -41,8 +41,8 @@ hysdn_card *card_root = NULL; /* pointer to first card */
 /* the last entry contains all 0              */
 /**********************************************/
 static struct {
-       word subid;             /* PCI sub id */
-       uchar cardtyp;          /* card type assigned */
+       unsigned short subid;           /* PCI sub id */
+       unsigned char cardtyp;          /* card type assigned */
 } pci_subid_map[] = {
 
        {
index aa01628d74c6f7db0459e26e0988098a3c471962..d205249a1242bb5d30fce1416bda6df69c2c3613 100644 (file)
@@ -24,7 +24,7 @@
 #include "hysdn_defs.h"
 
 unsigned int hynet_enable = 0xffffffff; 
-MODULE_PARM(hynet_enable, "i");
+module_param(hynet_enable, uint, 0);
 
 /* store the actual version for log reporting */
 char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
@@ -83,12 +83,12 @@ net_open(struct net_device *dev)
 
        /* Fill in the MAC-level header (if not already set) */
        if (!card->mac_addr[0]) {
-               for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
+               for (i = 0; i < ETH_ALEN - sizeof(unsigned long); i++)
                        dev->dev_addr[i] = 0xfc;
                if ((in_dev = dev->ip_ptr) != NULL) {
                        struct in_ifaddr *ifa = in_dev->ifa_list;
                        if (ifa != NULL)
-                               memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
+                               memcpy(dev->dev_addr + (ETH_ALEN - sizeof(unsigned long)), &ifa->ifa_local, sizeof(unsigned long));
                }
        } else
                memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
@@ -197,7 +197,7 @@ hysdn_tx_netack(hysdn_card * card)
 /* we got a packet from the network, go and queue it */
 /*****************************************************/
 void
-hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
+hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len)
 {
        struct net_local *lp = card->netif;
        struct sk_buff *skb;
index 6cd81b9b08bc45e49de2b6a28e5eb07c02e5d710..a368d6caca0ef092c09a3a3c42259515fddbf71b 100644 (file)
 
 /*--------------------------------------POF file record structs------------*/
 typedef struct PofFileHdr_tag {        /* Pof file header */
-/*00 */ ulong Magic __attribute__((packed));
-/*04 */ ulong N_PofRecs __attribute__((packed));
+/*00 */ unsigned long Magic __attribute__((packed));
+/*04 */ unsigned long N_PofRecs __attribute__((packed));
 /*08 */
 } tPofFileHdr;
 
 typedef struct PofRecHdr_tag { /* Pof record header */
-/*00 */ word PofRecId __attribute__((packed));
-/*02 */ ulong PofRecDataLen __attribute__((packed));
+/*00 */ unsigned short PofRecId __attribute__((packed));
+/*02 */ unsigned long PofRecDataLen __attribute__((packed));
 /*06 */
 } tPofRecHdr;
 
 typedef struct PofTimeStamp_tag {
-/*00 */ ulong UnixTime __attribute__((packed));
-       /*04 */ uchar DateTimeText[0x28] __attribute__((packed));
+/*00 */ unsigned long UnixTime __attribute__((packed));
+       /*04 */ unsigned char DateTimeText[0x28] __attribute__((packed));
        /* =40 */
 /*2C */
 } tPofTimeStamp;
index 40e56143c768fcecfd96296e53ebe1edfd173edb..8e2b03889f3cb0a6b6a8174eac5d7ef0ee34fe5f 100644 (file)
@@ -36,9 +36,9 @@ struct conf_writedata {
        int buf_size;           /* actual number of bytes in the buffer */
        int needed_size;        /* needed size when reading pof */
        int state;              /* actual interface states from above constants */
-       uchar conf_line[CONF_LINE_LEN];         /* buffered conf line */
-       word channel;           /* active channel number */
-       uchar *pof_buffer;      /* buffer when writing pof */
+       unsigned char conf_line[CONF_LINE_LEN]; /* buffered conf line */
+       unsigned short channel;         /* active channel number */
+       unsigned char *pof_buffer;      /* buffer when writing pof */
 };
 
 /***********************************************************************/
@@ -49,7 +49,7 @@ struct conf_writedata {
 static int
 process_line(struct conf_writedata *cnf)
 {
-       uchar *cp = cnf->conf_line;
+       unsigned char *cp = cnf->conf_line;
        int i;
 
        if (cnf->card->debug_flags & LOG_CNF_LINE)
@@ -92,7 +92,7 @@ hysdn_conf_write(struct file *file, const char __user *buf, size_t count, loff_t
 {
        struct conf_writedata *cnf;
        int i;
-       uchar ch, *cp;
+       unsigned char ch, *cp;
 
        if (!count)
                return (0);     /* nothing to handle */
@@ -390,7 +390,7 @@ int
 hysdn_procconf_init(void)
 {
        hysdn_card *card;
-       uchar conf_name[20];
+       unsigned char conf_name[20];
 
        hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, proc_net);
        if (!hysdn_proc_entry) {
@@ -423,7 +423,7 @@ void
 hysdn_procconf_release(void)
 {
        hysdn_card *card;
-       uchar conf_name[20];
+       unsigned char conf_name[20];
 
        card = card_root;       /* start with first card */
        while (card) {
index 6c26f1efabd52299c8a90fdc2eb170ff7510b738..c4301e8338eff58a4a01fc7f2120fbfeefe5dd3a 100644 (file)
@@ -28,7 +28,7 @@ static void put_log_buffer(hysdn_card * card, char *cp);
 /*************************************************/
 struct log_data {
        struct log_data *next;
-       ulong usage_cnt;        /* number of files still to work */
+       unsigned long usage_cnt;/* number of files still to work */
        void *proc_ctrl;        /* pointer to own control procdata structure */
        char log_start[2];      /* log string start (final len aligned by size) */
 };
@@ -42,7 +42,7 @@ struct procdata {
        struct log_data *log_head, *log_tail;   /* head and tail for queue */
        int if_used;            /* open count for interface */
        int volatile del_lock;  /* lock for delete operations */
-       uchar logtmp[LOG_MAX_LINELEN];
+       unsigned char logtmp[LOG_MAX_LINELEN];
        wait_queue_head_t rd_queue;
 };
 
@@ -153,9 +153,9 @@ put_log_buffer(hysdn_card * card, char *cp)
 static ssize_t
 hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
 {
-       ulong u = 0;
+       unsigned long u = 0;
        int found = 0;
-       uchar *cp, valbuf[128];
+       unsigned char *cp, valbuf[128];
        long base = 10;
        hysdn_card *card = (hysdn_card *) file->private_data;
 
@@ -249,7 +249,7 @@ hysdn_log_open(struct inode *ino, struct file *filep)
 {
        hysdn_card *card;
        struct procdata *pd = NULL;
-       ulong flags;
+       unsigned long flags;
 
        lock_kernel();
        card = card_root;
index 4fa3b01707cd2f72ecb7b9fbb377b224ab95b030..133032920ff8339d6b272de59cc277f5c79bb9db 100644 (file)
@@ -30,7 +30,8 @@
 /* to keep the data until later.                                             */
 /*****************************************************************************/
 int
-hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
+hysdn_sched_rx(hysdn_card *card, unsigned char *buf, unsigned short len,
+                       unsigned short chan)
 {
 
        switch (chan) {
@@ -72,7 +73,9 @@ hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
 /* sending.                                                                  */
 /*****************************************************************************/
 int
-hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
+hysdn_sched_tx(hysdn_card *card, unsigned char *buf,
+               unsigned short volatile *len, unsigned short volatile *chan,
+               unsigned short maxlen)
 {
        struct sk_buff *skb;
 
@@ -145,10 +148,10 @@ hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile
 /* are to be sent and this happens very seldom.                              */
 /*****************************************************************************/
 int
-hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
+hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan)
 {
        int cnt = 50;           /* timeout intervalls */
-       ulong flags;
+       unsigned long flags;
 
        if (card->debug_flags & LOG_SCHED_ASYN)
                hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
index 4a115a87c78216220ec21056da7f2e943a9baad4..7a36694df6d7082ddb254a3a68f5c0f7969a7357 100644 (file)
@@ -62,7 +62,7 @@
  *                     s. RotlCRC algorithm
  *
  *  RotlCRC algorithm:
- *      ucSum= 0                        1 uchar
+ *      ucSum= 0                        1 unsigned char
  *      for all NonEndTokenChunk bytes:
  *          ROTL(ucSum,1)               rotate left by 1
  *          ucSum += Char;              add current byte with swap around
 
 typedef struct ErrLogEntry_tag {
        
-/*00 */ ulong ulErrType;
+/*00 */ unsigned long ulErrType;
        
-/*04 */ ulong ulErrSubtype;
+/*04 */ unsigned long ulErrSubtype;
        
-/*08 */ uchar ucTextSize;
+/*08 */ unsigned char ucTextSize;
        
-       /*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
+       /*09 */ unsigned char ucText[ERRLOG_TEXT_SIZE];
        /* ASCIIZ of len ucTextSize-1 */
        
 /*40 */ 
@@ -111,13 +111,13 @@ typedef struct ErrLogEntry_tag {
 #define DPRAM_SPOOLER_DATA_SIZE 0x20
 typedef struct DpramBootSpooler_tag {
        
-/*00 */ uchar Len;
+/*00 */ unsigned char Len;
        
-/*01 */ volatile uchar RdPtr;
+/*01 */ volatile unsigned char RdPtr;
        
-/*02 */ uchar WrPtr;
+/*02 */ unsigned char WrPtr;
        
-/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
+/*03 */ unsigned char Data[DPRAM_SPOOLER_DATA_SIZE];
        
 /*23 */ 
 } tDpramBootSpooler;
index 1a19a0f894288907c30ea2fbb91790db3d67a584..b9fed8a3bcc650036e170719ac9d0320a602e4ac 100644 (file)
@@ -782,7 +782,8 @@ isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
        is->first = b;
 
        spin_unlock_irqrestore(&is->buflock, flags);
-       copy_to_user(buf, save_buf, count);
+       if (copy_to_user(buf, save_buf, count))
+               count = -EFAULT;
        kfree(save_buf);
 
        return count;
index aeaa1db74bd87ad37bd103655df01791e2676a18..3585fb1f334460ae69a3c24e32c0ee03d52def49 100644 (file)
@@ -2345,12 +2345,15 @@ isdn_tty_at_cout(char *msg, modem_info * info)
        u_long flags;
        struct sk_buff *skb = NULL;
        char *sp = NULL;
-       int l = strlen(msg);
+       int l;
 
        if (!msg) {
                printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
                return;
        }
+
+       l = strlen(msg);
+
        spin_lock_irqsave(&info->readlock, flags);
        tty = info->tty;
        if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
index 33d33970041173e54fe52cd25f21fe7e5275abf3..a67d31af797a78030c5653bd1bc1f6f05e29937e 100644 (file)
@@ -22,7 +22,7 @@ static char *isdnloop_id = "loop0";
 MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
 MODULE_AUTHOR("Fritz Elfert");
 MODULE_LICENSE("GPL");
-MODULE_PARM(isdnloop_id, "s");
+module_param(isdnloop_id, charp, 0);
 MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
 
 static int isdnloop_addcard(char *);
index 979e8cae5d837a7bb444dc703ec3e0718cea9e6f..e1c18aa1d71295705c19d76dc7dc7c663d6962fd 100644 (file)
@@ -556,7 +556,7 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
        unsigned long flags;
 
        spin_lock_irqsave(&bitmap->lock, flags);
-       if (!bitmap || !bitmap->sb_page) { /* can't set the state */
+       if (!bitmap->sb_page) { /* can't set the state */
                spin_unlock_irqrestore(&bitmap->lock, flags);
                return;
        }
index c2602b34049198c52fecec30caf4d5922eb9e633..baa9f58beffc73b1029f69cc17cf5eba259c7012 100644 (file)
@@ -50,5 +50,19 @@ config VIDEO_IR
 config VIDEO_TVEEPROM
        tristate
 
+config USB_DABUSB
+        tristate "DABUSB driver"
+        depends on USB
+        ---help---
+          A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
+          brought to you by the DAB-Team
+          <http://wwwbode.cs.tum.edu/Par/arch/dab/>.  This driver can be taken
+          as an example for URB-based bulk, control, and isochronous
+          transactions. URB's are explained in
+          <Documentation/usb/URB.txt>.
+
+          To compile this driver as a module, choose M here: the
+          module will be called dabusb.
+
 endmenu
 
index 3870fa948cc08356a5ec1a8a5bed2b7eadbb941d..523ab3851c7b8ad71609a4df77104c29bbd099be 100644 (file)
@@ -50,14 +50,15 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
 /********************************************************************************/
 /* common dma functions */
 
-void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf)
+void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
+                                               struct saa7146_buf *buf)
 {
        DEB_EE(("dev:%p, buf:%p\n",dev,buf));
 
        BUG_ON(in_interrupt());
 
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
+       videobuf_dma_unmap(q, &buf->vb.dma);
        videobuf_dma_free(&buf->vb.dma);
        buf->vb.state = STATE_NEEDS_INIT;
 }
index 500bd3f05e169b877090276e11e6a0c130ec7160..063608462ebe19222923c2a57ae010257eaca55e 100644 (file)
@@ -236,7 +236,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
        }
 
        if (buf->vb.size != size)
-               saa7146_dma_free(dev,buf);
+               saa7146_dma_free(dev,q,buf);
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
                buf->vb.width  = llength;
@@ -247,7 +247,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
                saa7146_pgtable_free(dev->pci, &buf->pt[2]);
                saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
 
-               err = videobuf_iolock(dev->pci,&buf->vb, NULL);
+               err = videobuf_iolock(q,&buf->vb, NULL);
                if (err)
                        goto oops;
                err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
@@ -261,7 +261,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 
  oops:
        DEB_VBI(("error out.\n"));
-       saa7146_dma_free(dev,buf);
+       saa7146_dma_free(dev,q,buf);
 
        return err;
 }
@@ -301,7 +301,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
        DEB_VBI(("vb:%p\n",vb));
-       saa7146_dma_free(dev,buf);
+       saa7146_dma_free(dev,q,buf);
 }
 
 static struct videobuf_queue_ops vbi_qops = {
index 6b42713d97f49d853ef1e3e980af0f67ccaa03df..e7079d1bd5371b19836788ec9064ed9c05a8d151 100644 (file)
@@ -1275,7 +1275,7 @@ static int buffer_prepare(struct videobuf_queue *q,
            buf->vb.field  != field      ||
            buf->vb.field  != fh->video_fmt.field  ||
            buf->fmt       != &fh->video_fmt) {
-               saa7146_dma_free(dev,buf);
+               saa7146_dma_free(dev,q,buf);
        }
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
@@ -1304,7 +1304,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                        saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
                }
 
-               err = videobuf_iolock(dev->pci,&buf->vb, &vv->ov_fb);
+               err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
                if (err)
                        goto oops;
                err = saa7146_pgtable_build(dev,buf);
@@ -1318,7 +1318,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 
  oops:
        DEB_D(("error out.\n"));
-       saa7146_dma_free(dev,buf);
+       saa7146_dma_free(dev,q,buf);
 
        return err;
 }
@@ -1363,7 +1363,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7146_buf *buf = (struct saa7146_buf *)vb;
 
        DEB_CAP(("vbuf:%p\n",vb));
-       saa7146_dma_free(dev,buf);
+       saa7146_dma_free(dev,q,buf);
 }
 
 static struct videobuf_queue_ops video_qops = {
index a6c91db40ad693b17a323a49034cf5b501f62eb0..06ec9fff0ec1e5f5d3293685e5f49d9c73a71421 100644 (file)
@@ -541,6 +541,7 @@ static struct usb_device_id flexcop_usb_table [] = {
            { USB_DEVICE(0x0af7, 0x0101) },
            { }
 };
+MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver flexcop_usb_driver = {
index d188e4c670b512f6667825a39117a14a6a843d08..9d197efb481d4a3f2f08cec1bda3f04882b0de83 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
index e14bf43941e33874554e7d39fc87c5525859f126..a14e737ec848df57f4147f62c139f2630a996b77 100644 (file)
@@ -81,18 +81,19 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
                return -EAGAIN;
 
        if (num > 2)
-               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+               warn("more than two i2c messages at a time is not handled yet. TODO.");
 
        for (i = 0; i < num; i++) {
 
-               switch (msg[i].addr) {
-                       case 0x63:
-                               cxusb_gpio_tuner(d,0);
-                               break;
-                       default:
-                               cxusb_gpio_tuner(d,1);
-                               break;
-               }
+               if (d->udev->descriptor.idVendor == USB_VID_MEDION)
+                       switch (msg[i].addr) {
+                               case 0x63:
+                                       cxusb_gpio_tuner(d,0);
+                                       break;
+                               default:
+                                       cxusb_gpio_tuner(d,1);
+                                       break;
+                       }
 
                /* read request */
                if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
@@ -108,7 +109,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
                                break;
 
                        if (ibuf[0] != 0x08)
-                               deb_info("i2c read could have been failed\n");
+                               deb_i2c("i2c read may have failed\n");
 
                        memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
 
@@ -122,7 +123,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
                        if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
                                break;
                        if (ibuf != 0x08)
-                               deb_info("i2c write could have been failed\n");
+                               deb_i2c("i2c write may have failed\n");
                }
        }
 
@@ -410,7 +411,6 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const
        if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
            fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
 
-               /* FIXME: are we allowed to change the fw-data ? */
                fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
                fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
 
index 087c99427853f6a51496b6598f7aec5bb8941859..c8ef77554b00a1cbff09faedd858ef898317a170 100644 (file)
@@ -6,6 +6,8 @@
 
 extern int dvb_usb_cxusb_debug;
 #define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
+                               dprintk(dvb_usb_cxusb_debug,0x01,args)
 
 /* usb commands - some of it are guesses, don't have a reference yet */
 #define CMD_I2C_WRITE     0x08
index 2f23ceab8d446491c73a3d832ec2c824733eb951..603a22e4bfe26a37669e784f1cd2172a02425b22 100644 (file)
@@ -369,6 +369,11 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                        fm_matrix = 0x3001; // stereo
                        src = 0x0020;
                        break;
+               case V4L2_TUNER_MODE_LANG1_LANG2:
+                       dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
+                       fm_matrix = 0x3000; // bilingual
+                       src = 0x0020;
+                       break;
                case V4L2_TUNER_MODE_LANG1:
                        dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
                        fm_matrix = 0x3000; // mono
index c622a4da5663a0d87db2335f49fcdbbd5d3c5c91..f31a19890b15d99969bc99d06f2042218654b0dc 100644 (file)
@@ -16,31 +16,7 @@ config VIDEO_ADV_DEBUG
          V4L devices.
          In doubt, say N.
 
-config VIDEO_BT848
-       tristate "BT848 Video For Linux"
-       depends on VIDEO_DEV && PCI && I2C
-       select I2C_ALGOBIT
-       select FW_LOADER
-       select VIDEO_BTCX
-       select VIDEO_BUF
-       select VIDEO_IR
-       select VIDEO_TUNER
-       select VIDEO_TVEEPROM
-       select VIDEO_MSP3400
-       ---help---
-         Support for BT848 based frame grabber/overlay boards. This includes
-         the Miro, Hauppauge and STB boards. Please read the material in
-         <file:Documentation/video4linux/bttv/> for more information.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bttv.
-
-config VIDEO_BT848_DVB
-       bool "DVB/ATSC Support for bt878 based TV cards"
-       depends on VIDEO_BT848 && DVB_CORE
-       select DVB_BT8XX
-       ---help---
-         This adds support for DVB/ATSC cards based on the BT878 chip.
+source "drivers/media/video/bt8xx/Kconfig"
 
 config VIDEO_SAA6588
        tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
@@ -315,8 +291,6 @@ config VIDEO_HEXIUM_GEMINI
 
 source "drivers/media/video/cx88/Kconfig"
 
-source "drivers/media/video/em28xx/Kconfig"
-
 config VIDEO_OVCAMCHIP
        tristate "OmniVision Camera Chip support"
        depends on VIDEO_DEV && I2C
@@ -391,4 +365,234 @@ config VIDEO_SAA7127
          To compile this driver as a module, choose M here: the
          module will be called saa7127
 
+#
+# USB Multimedia device configuration
+#
+
+menu "V4L USB devices"
+       depends on USB && VIDEO_DEV
+
+source "drivers/media/video/em28xx/Kconfig"
+
+config USB_VICAM
+       tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
+       depends on USB && VIDEO_DEV && EXPERIMENTAL
+       ---help---
+         Say Y here if you have 3com homeconnect camera (vicam).
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Multimedia Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vicam.
+
+config USB_DSBR
+       tristate "D-Link USB FM radio support (EXPERIMENTAL)"
+       depends on USB && VIDEO_DEV && EXPERIMENTAL
+       ---help---
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port. Note that the audio is not digital, and
+         you must connect the line out connector to a sound card or a
+         set of speakers.
+
+         This driver uses the Video For Linux API.  You must enable
+         (Y or M in config) Video For Linux (under Character Devices)
+         to use this driver.  Information on this API and pointers to
+         "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dsbr100.
+
+config USB_ET61X251
+       tristate "USB ET61X[12]51 PC Camera Controller support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on Etoms ET61X151
+         or ET61X251 PC Camera Controllers.
+
+         See <file:Documentation/usb/et61x251.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called et61x251.
+
+config USB_IBMCAM
+       tristate "USB IBM (Xirlink) C-it Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect a IBM "C-It" camera, also known as
+         "Xirlink PC Camera" to your computer's USB port.  For more
+         information, read <file:Documentation/usb/ibmcam.txt>.
+
+         This driver uses the Video For Linux API.  You must enable
+         (Y or M in config) Video For Linux (under Character Devices)
+         to use this driver.  Information on this API and pointers to
+         "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ibmcam.
+
+         This camera has several configuration options which
+         can be specified when you load the module. Read
+         <file:Documentation/usb/ibmcam.txt> to learn more.
+
+config USB_KONICAWC
+       tristate "USB Konica Webcam support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for webcams based on a Konica
+         chipset. This is known to work with the Intel YC76 webcam.
+
+         This driver uses the Video For Linux API.  You must enable
+         (Y or M in config) Video For Linux (under Character Devices)
+         to use this driver.  Information on this API and pointers to
+         "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called konicawc.
+
+config USB_OV511
+       tristate "USB OV511 Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port. See <file:Documentation/usb/ov511.txt> for more
+         information and for a list of supported cameras.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Character Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ov511.
+
+config USB_SE401
+       tristate "USB SE401 Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port. See <file:Documentation/usb/se401.txt> for more
+         information and for a list of supported cameras.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Multimedia Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called se401.
+
+config USB_SN9C102
+       tristate "USB SN9C10x PC Camera Controller support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on SONiX SN9C101,
+         SN9C102 or SN9C103 PC Camera Controllers.
+
+         See <file:Documentation/usb/sn9c102.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sn9c102.
+
+config USB_STV680
+       tristate "USB STV680 (Pencam) Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port. This includes the Pencam line of cameras.
+         See <file:Documentation/usb/stv680.txt> for more information and for
+         a list of supported cameras.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Multimedia Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stv680.
+
+config USB_W9968CF
+       tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+       depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP
+       ---help---
+         Say Y here if you want support for cameras based on OV681 or
+         Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
+
+         This driver has an optional plugin, which is distributed as a
+         separate module only (released under GPL). It allows to use higher
+         resolutions and framerates, but cannot be included in the official
+         Linux kernel for performance purposes.
+
+         See <file:Documentation/usb/w9968cf.txt> for more informations.
+
+         This driver uses the Video For Linux and the I2C APIs. It needs the
+         OmniVision Camera Chip support as well. You must say Y or M to
+         "Video For Linux", "I2C Support" and "OmniVision Camera Chip
+         support" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w9968cf.
+
+config USB_ZC0301
+       tristate "USB ZC0301 Image Processor and Control Chip support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on the ZC0301
+         Image Processor and Control Chip.
+
+         See <file:Documentation/usb/zc0301.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called zc0301.
+
+config USB_PWC
+       tristate "USB Philips Cameras"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y or M here if you want to use one of these Philips & OEM
+         webcams:
+          * Philips PCA645, PCA646
+          * Philips PCVC675, PCVC680, PCVC690
+          * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+          * Askey VC010
+          * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
+            and 'Orbit'/'Sphere'
+          * Samsung MPC-C10, MPC-C30
+          * Creative Webcam 5, Pro Ex
+          * SOTEC Afina Eye
+          * Visionite VCS-UC300, VCS-UM100
+
+         The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
+         and never will be, but the 665 and 720/20 are supported by other
+         drivers.
+
+         See <file:Documentation/usb/philips.txt> for more information and
+         installation instructions.
+
+         The built-in microphone is enabled by selecting USB Audio support.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Character Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pwc.
+
+endmenu # V4L USB devices
+
 endmenu
index f2bd4c0c4f10f5f0215a18d14d6533d88e6f8664..1c0e72e5a593ac6a44e133fc16f25aa409afc50e 100644 (file)
@@ -2,9 +2,6 @@
 # Makefile for the video capture/playback device drivers.
 #
 
-bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
-                       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
-                       bttv-input.o
 zoran-objs      :=     zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
@@ -15,8 +12,8 @@ msp3400-objs  :=      msp3400-driver.o msp3400-kthreads.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
 
-obj-$(CONFIG_VIDEO_BT848) += bttv.o tvaudio.o \
-       tda7432.o tda9875.o ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_BT848) += tvaudio.o tda7432.o tda9875.o ir-kbd-i2c.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
@@ -68,4 +65,23 @@ obj-$(CONFIG_VIDEO_CX25840) += cx25840/
 obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 
+et61x251-objs   := et61x251_core.o et61x251_tas5130d1b.o
+zc0301-objs     := zc0301_core.o zc0301_pas202bcb.o
+
+obj-$(CONFIG_USB_DABUSB)        += dabusb.o
+obj-$(CONFIG_USB_DSBR)          += dsbr100.o
+obj-$(CONFIG_USB_OV511)         += ov511.o
+obj-$(CONFIG_USB_SE401)         += se401.o
+obj-$(CONFIG_USB_STV680)        += stv680.o
+obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
+
+obj-$(CONFIG_USB_SN9C102)       += sn9c102/
+obj-$(CONFIG_USB_ET61X251)      += et61x251/
+obj-$(CONFIG_USB_PWC)           += pwc/
+obj-$(CONFIG_USB_ZC0301)        += zc0301/
+
+obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
+obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
+obj-$(CONFIG_USB_VICAM)         += usbvideo/
+
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
index 671e36db224d44902ccc273745fa66e1e10940db..48709582a18612400040d91a53e4368cb0cf2081 100644 (file)
@@ -1,9 +1,9 @@
-/* 
+/*
  * adv7170 - adv7170, adv7171 video encoder driver version 0.0.1
  *
  * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
  *
- * Based on adv7176 driver by:    
+ * Based on adv7176 driver by:
  *
  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
  * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
@@ -173,7 +173,7 @@ adv7170_write_block (struct i2c_client *client,
 static const unsigned char init_NTSC[] = {
        0x00, 0x10,             // MR0
        0x01, 0x20,             // MR1
-       0x02, 0x0e,             // MR2 RTC control: bits 2 and 1 
+       0x02, 0x0e,             // MR2 RTC control: bits 2 and 1
        0x03, 0x80,             // MR3
        0x04, 0x30,             // MR4
        0x05, 0x00,             // Reserved
@@ -196,7 +196,7 @@ static const unsigned char init_NTSC[] = {
        0x16, 0x00,             // CGMS_WSS_0
        0x17, 0x00,             // CGMS_WSS_1
        0x18, 0x00,             // CGMS_WSS_2
-       0x19, 0x00,             // Teletext Ctl 
+       0x19, 0x00,             // Teletext Ctl
 };
 
 static const unsigned char init_PAL[] = {
@@ -381,7 +381,7 @@ static unsigned short normal_i2c[] =
 };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
index 085e8863cacbe6a91ff8c9884a89abe74f7e3d5c..68e7d7aff5e6423b4bf51386473fe6c6d2c62663 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  *  adv7175 - adv7175a video encoder driver version 0.0.3
  *
  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
@@ -233,7 +233,7 @@ adv7175_command (struct i2c_client *client,
                                    sizeof(init_common));
                adv7175_write(client, 0x07, TR0MODE | TR0RST);
                adv7175_write(client, 0x07, TR0MODE);
-               break;
+               break;
 
        case ENCODER_GET_CAPABILITIES:
        {
@@ -399,7 +399,7 @@ static unsigned short normal_i2c[] =
 };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
index c586f64b6b7f20fb7d1e38016c4a90ed983bae16..dbe025170599df7c11bcd03b5730d8d05e717886 100644 (file)
@@ -161,39 +161,39 @@ void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2,
 {
        int i;
 
-       /* Slave Address */
-       ar_outl(addr, PLDI2CDATA);
+       /* Slave Address */
+       ar_outl(addr, PLDI2CDATA);
        wait_for_vsync();
 
-       /* Start */
-       ar_outl(1, PLDI2CCND);
+       /* Start */
+       ar_outl(1, PLDI2CCND);
        wait_acknowledge();
 
        /* Transfer data 1 */
-       ar_outl(data1, PLDI2CDATA);
+       ar_outl(data1, PLDI2CDATA);
        wait_for_vsync();
-       ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+       ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
        wait_acknowledge();
 
        /* Transfer data 2 */
-       ar_outl(data2, PLDI2CDATA);
+       ar_outl(data2, PLDI2CDATA);
        wait_for_vsync();
-       ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+       ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
        wait_acknowledge();
 
        if (n == 3) {
                /* Transfer data 3 */
-               ar_outl(data3, PLDI2CDATA);
+               ar_outl(data3, PLDI2CDATA);
                wait_for_vsync();
-               ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+               ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
                wait_acknowledge();
-       }
+       }
 
-       /* Stop */
+       /* Stop */
        for (i = 0; i < 100; i++)
                cpu_relax();
-       ar_outl(2, PLDI2CCND);
-       ar_outl(2, PLDI2CCND);
+       ar_outl(2, PLDI2CCND);
+       ar_outl(2, PLDI2CCND);
 
        while (ar_inl(PLDI2CSTS) & PLDI2CSTS_BB)
                cpu_relax();
@@ -204,24 +204,24 @@ void init_iic(void)
 {
        DEBUG(1, "init_iic:\n");
 
-       /*
+       /*
         * ICU Setting (iic)
         */
-       /* I2C Setting */
-       ar_outl(0x0, PLDI2CCR);         /* I2CCR Disable                   */
-       ar_outl(0x0300, PLDI2CMOD);     /* I2CMOD ACK/8b-data/7b-addr/auto */
-       ar_outl(0x1, PLDI2CACK);        /* I2CACK ACK                      */
+       /* I2C Setting */
+       ar_outl(0x0, PLDI2CCR);         /* I2CCR Disable                   */
+       ar_outl(0x0300, PLDI2CMOD);     /* I2CMOD ACK/8b-data/7b-addr/auto */
+       ar_outl(0x1, PLDI2CACK);        /* I2CACK ACK                      */
 
        /* I2C CLK */
-       /* 50MH-100k */
+       /* 50MH-100k */
        if (freq == 75) {
-               ar_outl(369, PLDI2CFREQ);       /* BCLK = 75MHz */
+               ar_outl(369, PLDI2CFREQ);       /* BCLK = 75MHz */
        } else if (freq == 50) {
                ar_outl(244, PLDI2CFREQ);       /* BCLK = 50MHz */
        } else {
                ar_outl(244, PLDI2CFREQ);       /* default: BCLK = 50MHz */
        }
-       ar_outl(0x1, PLDI2CCR);         /* I2CCR Enable */
+       ar_outl(0x1, PLDI2CCR);         /* I2CCR Enable */
 }
 
 /**************************************************************************
@@ -253,7 +253,7 @@ static inline void wait_for_vertical_sync(int exp_line)
 
        /*
         * check HCOUNT because we cannot check vertical sync.
-        */
+        */
        for (; tmout >= 0; tmout--) {
                l = ar_inl(ARVHCOUNT);
                if (l == exp_line)
@@ -562,8 +562,8 @@ static void ar_interrupt(int irq, void *dev, struct pt_regs *regs)
                /* operations for interlace mode */
                if ( line_count < (AR_HEIGHT_VGA/2) )   /* even line */
                        line_number = (line_count << 1);
-               else                                    /* odd line */
-                       line_number =
+               else                                    /* odd line */
+                       line_number =
                        (((line_count - (AR_HEIGHT_VGA/2)) << 1) + 1);
        } else {
                line_number = line_count;
@@ -651,7 +651,7 @@ static int ar_initialize(struct video_device *dev)
                cr |= ARVCR1_NORMAL;
        ar_outl(cr, ARVCR1);
 
-       /*
+       /*
         * Initialize IIC so that CPU can communicate with AR LSI,
         * and send boot commands to AR LSI.
         */
@@ -846,7 +846,7 @@ static int __init ar_init(void)
         * so register video device as a frame grabber type.
         * device is named "video[0-64]".
         * video_register_device() initializes h/w using ar_initialize().
-        */
+        */
        if (video_register_device(ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) {
                /* return -1, -ENFILE(full) or others */
                printk("arv: register video (Colour AR) failed.\n");
index d8a18a6a5bee175435b3b996687730d4c638a591..e7b38fdd5e3c9389e2032ca1c8c5103a19a120a1 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  *  bt819 - BT819A VideoStream Decoder (Rockwell Part)
  *
  * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
@@ -6,7 +6,7 @@
  *
  * Modifications for LML33/DC10plus unified driver
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
- *  
+ *
  * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
  *    - moved over to linux>=2.4.x i2c protocol (9/9/2002)
  *
@@ -206,9 +206,9 @@ bt819_init (struct i2c_client *client)
                                           Bug in the bt819 stepping on my board?
                                        */
                0x14, 0x00,     /* 0x14 Vertial Scaling lsb */
-               0x16, 0x07,     /* 0x16 Video Timing Polarity 
+               0x16, 0x07,     /* 0x16 Video Timing Polarity
                                           ACTIVE=active low
-                                          FIELD: high=odd, 
+                                          FIELD: high=odd,
                                           vreset=active high,
                                           hreset=active high */
                0x18, 0x68,     /* 0x18 AGC Delay */
@@ -497,7 +497,7 @@ static unsigned short normal_i2c[] = {
 };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
deleted file mode 100644 (file)
index cc54b62..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Driver for Bt832 CMOS Camera Video Processor
-    i2c-addresses: 0x88 or 0x8a
-
-  The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
-  via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
-  It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
-  connected to bt848/bt878 GPIO pins on this purpose.
-  (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
-
-  Supported Cards:
-  -  Pixelview Rev.4E: 0x8a
-               GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
-
-  (c) Gunther Mayer, 2002
-
-  STATUS:
-  - detect chip and hexdump
-  - reset chip and leave low power mode
-  - detect camera present
-
-  TODO:
-  - make it work (find correct setup for Bt832 and Bt878)
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <media/audiochip.h>
-#include <media/v4l2-common.h>
-
-#include "bttv.h"
-#include "bt832.h"
-
-MODULE_LICENSE("GPL");
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
-                                      I2C_CLIENT_END };
-I2C_CLIENT_INSMOD;
-
-int debug;    /* debug output */
-module_param(debug,            int, 0644);
-
-/* ---------------------------------------------------------------------- */
-
-static int bt832_detach(struct i2c_client *client);
-
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-struct bt832 {
-       struct i2c_client client;
-};
-
-int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
-{
-       int i,rc;
-       buf[0]=0x80; // start at register 0 with auto-increment
-       if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
-               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
-
-       for(i=0;i<65;i++)
-               buf[i]=0;
-       if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
-               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
-
-       // Note: On READ the first byte is the current index
-       //  (e.g. 0x80, what we just wrote)
-
-       if(debug>1) {
-               int i;
-               v4l_dbg(2, debug,i2c_client_s,"hexdump:");
-               for(i=1;i<65;i++) {
-                       if(i!=1) {
-                               if(((i-1)%8)==0) printk(" ");
-                               if(((i-1)%16)==0) {
-                                       printk("\n");
-                                       v4l_dbg(2, debug,i2c_client_s,"hexdump:");
-                               }
-                       }
-                       printk(" %02x",buf[i]);
-               }
-               printk("\n");
-       }
-       return 0;
-}
-
-// Return: 1 (is a bt832), 0 (No bt832 here)
-int bt832_init(struct i2c_client *i2c_client_s)
-{
-       unsigned char *buf;
-       int rc;
-
-       buf=kmalloc(65,GFP_KERNEL);
-       bt832_hexdump(i2c_client_s,buf);
-
-       if(buf[0x40] != 0x31) {
-               v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
-               kfree(buf);
-               return 0;
-       }
-
-       v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
-       buf[0]=BT832_VP_STATUS; // Reg.52
-       buf[1]= 0x00;
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-
-       // Leave low power mode:
-       v4l_err(i2c_client_s,"leave low power mode.\n");
-       buf[0]=BT832_CAM_SETUP0; //0x39 57
-       buf[1]=0x08;
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-       v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
-       buf[0]=BT832_VP_STATUS; // Reg.52
-       buf[1]= 0x00;
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-
-       // Enable Output
-       v4l_info(i2c_client_s,"Enable Output\n");
-       buf[0]=BT832_VP_CONTROL1; // Reg.40
-       buf[1]= 0x27 & (~0x01); // Default | !skip
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-
-       // for testing (even works when no camera attached)
-       v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
-       buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
-       buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
-
-       v4l_info(i2c_client_s,"Camera Present: %s\n",
-               (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
-
-       bt832_hexdump(i2c_client_s,buf);
-       kfree(buf);
-       return 1;
-}
-
-
-
-static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       struct bt832 *t;
-
-       client_template.adapter = adap;
-       client_template.addr    = addr;
-
-       if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
-               return -ENOMEM;
-       t->client = client_template;
-       i2c_set_clientdata(&t->client, t);
-       i2c_attach_client(&t->client);
-
-       v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
-
-
-       if(! bt832_init(&t->client)) {
-               bt832_detach(&t->client);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int bt832_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, bt832_attach);
-       return 0;
-}
-
-static int bt832_detach(struct i2c_client *client)
-{
-       struct bt832 *t = i2c_get_clientdata(client);
-
-       v4l_info(&t->client,"dettach\n");
-       i2c_detach_client(client);
-       kfree(t);
-       return 0;
-}
-
-static int
-bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct bt832 *t = i2c_get_clientdata(client);
-
-       if (debug>1)
-               v4l_i2c_print_ioctl(&t->client,cmd);
-
-       switch (cmd) {
-               case BT832_HEXDUMP: {
-                       unsigned char *buf;
-                       buf=kmalloc(65,GFP_KERNEL);
-                       bt832_hexdump(&t->client,buf);
-                       kfree(buf);
-               }
-               break;
-               case BT832_REATTACH:
-                       v4l_info(&t->client,"re-attach\n");
-                       i2c_del_driver(&driver);
-                       i2c_add_driver(&driver);
-               break;
-       }
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "bt832",
-       },
-       .id             = 0, /* FIXME */
-       .attach_adapter = bt832_probe,
-       .detach_client  = bt832_detach,
-       .command        = bt832_command,
-};
-static struct i2c_client client_template =
-{
-       .name       = "bt832",
-       .driver     = &driver,
-};
-
-
-static int __init bt832_init_module(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit bt832_cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(bt832_init_module);
-module_exit(bt832_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bt832.h b/drivers/media/video/bt832.h
deleted file mode 100644 (file)
index 1ce8fa7..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/* Bt832 CMOS Camera Video Processor (VP)
-
- The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
-  color digital camera directly to video capture devices via an 8-bit,
-  4:2:2 YUV or YCrCb video interface.
-
- i2c addresses: 0x88 or 0x8a
- */
-
-/* The 64 registers: */
-
-// Input Processor
-#define BT832_OFFSET 0
-#define BT832_RCOMP    1
-#define BT832_G1COMP   2
-#define BT832_G2COMP   3
-#define BT832_BCOMP    4
-// Exposures:
-#define BT832_FINEH    5
-#define BT832_FINEL    6
-#define BT832_COARSEH  7
-#define BT832_COARSEL   8
-#define BT832_CAMGAIN  9
-// Main Processor:
-#define BT832_M00      10
-#define BT832_M01      11
-#define BT832_M02      12
-#define BT832_M10      13
-#define BT832_M11      14
-#define BT832_M12      15
-#define BT832_M20      16
-#define BT832_M21      17
-#define BT832_M22      18
-#define BT832_APCOR    19
-#define BT832_GAMCOR   20
-// Level Accumulator Inputs
-#define BT832_VPCONTROL2       21
-#define BT832_ZONECODE0        22
-#define BT832_ZONECODE1        23
-#define BT832_ZONECODE2        24
-#define BT832_ZONECODE3        25
-// Level Accumulator Outputs:
-#define BT832_RACC     26
-#define BT832_GACC     27
-#define BT832_BACC     28
-#define BT832_BLACKACC 29
-#define BT832_EXP_AGC  30
-#define BT832_LACC0    31
-#define BT832_LACC1    32
-#define BT832_LACC2    33
-#define BT832_LACC3    34
-#define BT832_LACC4    35
-#define BT832_LACC5    36
-#define BT832_LACC6    37
-#define BT832_LACC7    38
-// System:
-#define BT832_VP_CONTROL0      39
-#define BT832_VP_CONTROL1      40
-#define BT832_THRESH   41
-#define BT832_VP_TESTCONTROL0  42
-#define BT832_VP_DMCODE        43
-#define BT832_ACB_CONFIG       44
-#define BT832_ACB_GNBASE       45
-#define BT832_ACB_MU   46
-#define BT832_CAM_TEST0        47
-#define BT832_AEC_CONFIG       48
-#define BT832_AEC_TL   49
-#define BT832_AEC_TC   50
-#define BT832_AEC_TH   51
-// Status:
-#define BT832_VP_STATUS        52
-#define BT832_VP_LINECOUNT     53
-#define BT832_CAM_DEVICEL      54 // e.g. 0x19
-#define BT832_CAM_DEVICEH      55 // e.g. 0x40  == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
-#define BT832_CAM_STATUS               56
- #define BT832_56_CAMERA_PRESENT 0x20
-//Camera Setups:
-#define BT832_CAM_SETUP0       57
-#define BT832_CAM_SETUP1       58
-#define BT832_CAM_SETUP2       59
-#define BT832_CAM_SETUP3       60
-// System:
-#define BT832_DEFCOR           61
-#define BT832_VP_TESTCONTROL1  62
-#define BT832_DEVICE_ID                63
-# define BT832_DEVICE_ID__31           0x31 // Bt832 has ID 0x31
-
-/* STMicroelectronivcs VV5404 camera module
-   i2c: 0x20: sensor address
-   i2c: 0xa0: eeprom for ccd defect map
- */
-#define VV5404_device_h                0x00  // 0x19
-#define VV5404_device_l                0x01  // 0x40
-#define VV5404_status0         0x02
-#define VV5404_linecountc      0x03 // current line counter
-#define VV5404_linecountl      0x04
-#define VV5404_setup0          0x10
-#define VV5404_setup1          0x11
-#define VV5404_setup2          0x12
-#define VV5404_setup4          0x14
-#define VV5404_setup5          0x15
-#define VV5404_fine_h          0x20  // fine exposure
-#define VV5404_fine_l          0x21
-#define VV5404_coarse_h                0x22  //coarse exposure
-#define VV5404_coarse_l                0x23
-#define VV5404_gain            0x24 // ADC pre-amp gain setting
-#define VV5404_clk_div         0x25
-#define VV5404_cr              0x76 // control register
-#define VV5404_as0             0x77 // ADC setup register
-
-
-// IOCTL
-#define BT832_HEXDUMP   _IOR('b',1,int)
-#define BT832_REATTACH _IOR('b',2,int)
-
-/* from BT8x8VXD/capdrv/dialogs.cpp */
-
-/*
-typedef enum { SVI, Logitech, Rockwell } CAMERA;
-
-static COMBOBOX_ENTRY gwCameraOptions[] =
-{
-   { SVI,      "Silicon Vision 512N" },
-   { Logitech, "Logitech VideoMan 1.3"  },
-   { Rockwell, "Rockwell QuartzSight PCI 1.0"   }
-};
-
-// SRAM table values
-//===========================================================================
-typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
-
-BYTE SRAMTable[][ 60 ] =
-{
-   // TGB_NTSC624
-   {
-      0x33, // size of table = 51
-      0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
-      0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
-      0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
-      0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
-      0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
-   },
-   // TGB_NTSC780
-   {
-      0x33, // size of table = 51
-      0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
-      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
-      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
-      0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
-      0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
-   },
-   // TGB_NTSC858
-   {
-      0x33, // size of table = 51
-      0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
-      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
-      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
-      0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
-      0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
-   },
-   // TGB_NTSC392
-   // This table has been modified to be used for Fusion Rev D
-   {
-      0x2A, // size of table = 42
-      0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
-      0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
-      0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
-      0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
-      0x20, 0x00
-   }
-};
-
-//===========================================================================
-// This is the structure of the camera specifications
-//===========================================================================
-typedef struct tag_cameraSpec
-{
-   SignalFormat signal;       // which digital signal format the camera has
-   VideoFormat  vidFormat;    // video standard
-   SyncVideoRef syncRef;      // which sync video reference is used
-   State        syncOutput;   // enable sync output for sync video input?
-   DecInputClk  iClk;         // which input clock is used
-   TimeGenByte  tgb;          // which timing generator byte does the camera use
-   int          HReset;       // select 64, 48, 32, or 16 CLKx1 for HReset
-   PLLFreq      pllFreq;      // what synthesized frequency to set PLL to
-   VSIZEPARMS   vSize;        // video size the camera produces
-   int          lineCount;    // expected total number of half-line per frame - 1
-   BOOL         interlace;    // interlace signal?
-} CameraSpec;
-
-//===========================================================================
-// <UPDATE REQUIRED>
-// Camera specifications database. Update this table whenever camera spec
-// has been changed or added/deleted supported camera models
-//===========================================================================
-static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
-{  // Silicon Vision 512N
-   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
-      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
-   {         512,           0x64,       480,    0x13,      240 },         0,       TRUE
-   },
-   // Logitech VideoMan 1.3
-   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
-      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
-      {      640,           0x80,       480,    0x1A,      240 },         0,       TRUE
-   },
-   // Rockwell QuartzSight
-   // Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
-   //       Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
-   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
-      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
-      {      352,           0x20,       576,    0x08,      288 },       607,       FALSE
-   }
-};
-*/
-
-/*
-The corresponding APIs required to be invoked are:
-SetConnector( ConCamera, TRUE/FALSE );
-SetSignalFormat( spec.signal );
-SetVideoFormat( spec.vidFormat );
-SetSyncVideoRef( spec.syncRef );
-SetEnableSyncOutput( spec.syncOutput );
-SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
-SetHReset( spec.HReset );
-SetPLL( spec.pllFreq );
-SetDecInputClock( spec.iClk );
-SetVideoInfo( spec.vSize );
-SetTotalLineCount( spec.lineCount );
-SetInterlaceMode( spec.interlace );
-*/
-
-/* from web:
- Video Sampling
-Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
-                 Pixel Clock   Horiz    Horiz    Vert
-                  Rate         Total    Active
-NTSC square pixel  12.27 MHz    780      640      525
-NTSC CCIR-601      13.5  MHz    858      720      525
-NTSC 4FSc          14.32 MHz    910      768      525
-PAL  square pixel  14.75 MHz    944      768      625
-PAL  CCIR-601      13.5  MHz    864      720      625
-PAL  4FSc          17.72 MHz   1135      948      625
-
-For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
-*/
-
-/* from DScaler:*/
-/*
-//===========================================================================
-// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
-//
-// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
-//
-
-//===========================================================================
-// Timing generator SRAM table values for CCIR601 720x480 NTSC
-//===========================================================================
-// For NTSC CCIR656
-BYTE BtCard::SRAMTable_NTSC[] =
-{
-    // SRAM Timing Table for NTSC
-    0x0c, 0xc0, 0x00,
-    0x00, 0x90, 0xc2,
-    0x03, 0x10, 0x03,
-    0x06, 0x10, 0x34,
-    0x12, 0x12, 0x65,
-    0x02, 0x13, 0x24,
-    0x19, 0x00, 0x24,
-    0x39, 0x00, 0x96,
-    0x59, 0x08, 0x93,
-    0x83, 0x08, 0x97,
-    0x03, 0x50, 0x30,
-    0xc0, 0x40, 0x30,
-    0x86, 0x01, 0x01,
-    0xa6, 0x0d, 0x62,
-    0x03, 0x11, 0x61,
-    0x05, 0x37, 0x30,
-    0xac, 0x21, 0x50
-};
-
-//===========================================================================
-// Timing generator SRAM table values for CCIR601 720x576 NTSC
-//===========================================================================
-// For PAL CCIR656
-BYTE BtCard::SRAMTable_PAL[] =
-{
-    // SRAM Timing Table for PAL
-    0x36, 0x11, 0x01,
-    0x00, 0x90, 0x02,
-    0x05, 0x10, 0x04,
-    0x16, 0x14, 0x05,
-    0x11, 0x00, 0x04,
-    0x12, 0xc0, 0x00,
-    0x31, 0x00, 0x06,
-    0x51, 0x08, 0x03,
-    0x89, 0x08, 0x07,
-    0xc0, 0x44, 0x00,
-    0x81, 0x01, 0x01,
-    0xa9, 0x0d, 0x02,
-    0x02, 0x50, 0x03,
-    0x37, 0x3d, 0x00,
-    0xaf, 0x21, 0x00,
-};
-*/
diff --git a/drivers/media/video/bt848.h b/drivers/media/video/bt848.h
deleted file mode 100644 (file)
index 0bcd953..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
-    bt848.h - Bt848 register offsets
-
-    Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _BT848_H_
-#define _BT848_H_
-
-#ifndef PCI_VENDOR_ID_BROOKTREE
-#define PCI_VENDOR_ID_BROOKTREE 0x109e
-#endif
-#ifndef PCI_DEVICE_ID_BT848
-#define PCI_DEVICE_ID_BT848     0x350
-#endif
-#ifndef PCI_DEVICE_ID_BT849
-#define PCI_DEVICE_ID_BT849     0x351
-#endif
-#ifndef PCI_DEVICE_ID_BT878
-#define PCI_DEVICE_ID_BT878     0x36e
-#endif
-#ifndef PCI_DEVICE_ID_BT879
-#define PCI_DEVICE_ID_BT879     0x36f
-#endif
-
-
-/* Brooktree 848 registers */
-
-#define BT848_DSTATUS          0x000
-#define BT848_DSTATUS_PRES     (1<<7)
-#define BT848_DSTATUS_HLOC     (1<<6)
-#define BT848_DSTATUS_FIELD    (1<<5)
-#define BT848_DSTATUS_NUML     (1<<4)
-#define BT848_DSTATUS_CSEL     (1<<3)
-#define BT848_DSTATUS_PLOCK    (1<<2)
-#define BT848_DSTATUS_LOF      (1<<1)
-#define BT848_DSTATUS_COF      (1<<0)
-
-#define BT848_IFORM            0x004
-#define BT848_IFORM_HACTIVE    (1<<7)
-#define BT848_IFORM_MUXSEL     (3<<5)
-#define BT848_IFORM_MUX0       (2<<5)
-#define BT848_IFORM_MUX1       (3<<5)
-#define BT848_IFORM_MUX2       (1<<5)
-#define BT848_IFORM_XTSEL      (3<<3)
-#define BT848_IFORM_XT0        (1<<3)
-#define BT848_IFORM_XT1        (2<<3)
-#define BT848_IFORM_XTAUTO     (3<<3)
-#define BT848_IFORM_XTBOTH     (3<<3)
-#define BT848_IFORM_NTSC       1
-#define BT848_IFORM_NTSC_J     2
-#define BT848_IFORM_PAL_BDGHI  3
-#define BT848_IFORM_PAL_M      4
-#define BT848_IFORM_PAL_N      5
-#define BT848_IFORM_SECAM      6
-#define BT848_IFORM_PAL_NC     7
-#define BT848_IFORM_AUTO       0
-#define BT848_IFORM_NORM       7
-
-#define BT848_TDEC             0x008
-#define BT848_TDEC_DEC_FIELD   (1<<7)
-#define BT848_TDEC_FLDALIGN    (1<<6)
-#define BT848_TDEC_DEC_RAT     (0x1f)
-
-#define BT848_E_CROP           0x00C
-#define BT848_O_CROP           0x08C
-
-#define BT848_E_VDELAY_LO      0x010
-#define BT848_O_VDELAY_LO      0x090
-
-#define BT848_E_VACTIVE_LO     0x014
-#define BT848_O_VACTIVE_LO     0x094
-
-#define BT848_E_HDELAY_LO      0x018
-#define BT848_O_HDELAY_LO      0x098
-
-#define BT848_E_HACTIVE_LO     0x01C
-#define BT848_O_HACTIVE_LO     0x09C
-
-#define BT848_E_HSCALE_HI      0x020
-#define BT848_O_HSCALE_HI      0x0A0
-
-#define BT848_E_HSCALE_LO      0x024
-#define BT848_O_HSCALE_LO      0x0A4
-
-#define BT848_BRIGHT           0x028
-
-#define BT848_E_CONTROL        0x02C
-#define BT848_O_CONTROL        0x0AC
-#define BT848_CONTROL_LNOTCH    (1<<7)
-#define BT848_CONTROL_COMP      (1<<6)
-#define BT848_CONTROL_LDEC      (1<<5)
-#define BT848_CONTROL_CBSENSE   (1<<4)
-#define BT848_CONTROL_CON_MSB   (1<<2)
-#define BT848_CONTROL_SAT_U_MSB (1<<1)
-#define BT848_CONTROL_SAT_V_MSB (1<<0)
-
-#define BT848_CONTRAST_LO      0x030
-#define BT848_SAT_U_LO         0x034
-#define BT848_SAT_V_LO         0x038
-#define BT848_HUE              0x03C
-
-#define BT848_E_SCLOOP         0x040
-#define BT848_O_SCLOOP         0x0C0
-#define BT848_SCLOOP_CAGC       (1<<6)
-#define BT848_SCLOOP_CKILL      (1<<5)
-#define BT848_SCLOOP_HFILT_AUTO (0<<3)
-#define BT848_SCLOOP_HFILT_CIF  (1<<3)
-#define BT848_SCLOOP_HFILT_QCIF (2<<3)
-#define BT848_SCLOOP_HFILT_ICON (3<<3)
-
-#define BT848_SCLOOP_PEAK       (1<<7)
-#define BT848_SCLOOP_HFILT_MINP (1<<3)
-#define BT848_SCLOOP_HFILT_MEDP (2<<3)
-#define BT848_SCLOOP_HFILT_MAXP (3<<3)
-
-
-#define BT848_OFORM            0x048
-#define BT848_OFORM_RANGE      (1<<7)
-#define BT848_OFORM_CORE0      (0<<5)
-#define BT848_OFORM_CORE8      (1<<5)
-#define BT848_OFORM_CORE16     (2<<5)
-#define BT848_OFORM_CORE32     (3<<5)
-
-#define BT848_E_VSCALE_HI      0x04C
-#define BT848_O_VSCALE_HI      0x0CC
-#define BT848_VSCALE_YCOMB     (1<<7)
-#define BT848_VSCALE_COMB      (1<<6)
-#define BT848_VSCALE_INT       (1<<5)
-#define BT848_VSCALE_HI        15
-
-#define BT848_E_VSCALE_LO      0x050
-#define BT848_O_VSCALE_LO      0x0D0
-#define BT848_TEST             0x054
-#define BT848_ADELAY           0x060
-#define BT848_BDELAY           0x064
-
-#define BT848_ADC              0x068
-#define BT848_ADC_RESERVED     (2<<6)
-#define BT848_ADC_SYNC_T       (1<<5)
-#define BT848_ADC_AGC_EN       (1<<4)
-#define BT848_ADC_CLK_SLEEP    (1<<3)
-#define BT848_ADC_Y_SLEEP      (1<<2)
-#define BT848_ADC_C_SLEEP      (1<<1)
-#define BT848_ADC_CRUSH        (1<<0)
-
-#define BT848_WC_UP            0x044
-#define BT848_WC_DOWN          0x078
-
-#define BT848_E_VTC            0x06C
-#define BT848_O_VTC            0x0EC
-#define BT848_VTC_HSFMT        (1<<7)
-#define BT848_VTC_VFILT_2TAP   0
-#define BT848_VTC_VFILT_3TAP   1
-#define BT848_VTC_VFILT_4TAP   2
-#define BT848_VTC_VFILT_5TAP   3
-
-#define BT848_SRESET           0x07C
-
-#define BT848_COLOR_FMT             0x0D4
-#define BT848_COLOR_FMT_O_RGB32     (0<<4)
-#define BT848_COLOR_FMT_O_RGB24     (1<<4)
-#define BT848_COLOR_FMT_O_RGB16     (2<<4)
-#define BT848_COLOR_FMT_O_RGB15     (3<<4)
-#define BT848_COLOR_FMT_O_YUY2      (4<<4)
-#define BT848_COLOR_FMT_O_BtYUV     (5<<4)
-#define BT848_COLOR_FMT_O_Y8        (6<<4)
-#define BT848_COLOR_FMT_O_RGB8      (7<<4)
-#define BT848_COLOR_FMT_O_YCrCb422  (8<<4)
-#define BT848_COLOR_FMT_O_YCrCb411  (9<<4)
-#define BT848_COLOR_FMT_O_RAW       (14<<4)
-#define BT848_COLOR_FMT_E_RGB32     0
-#define BT848_COLOR_FMT_E_RGB24     1
-#define BT848_COLOR_FMT_E_RGB16     2
-#define BT848_COLOR_FMT_E_RGB15     3
-#define BT848_COLOR_FMT_E_YUY2      4
-#define BT848_COLOR_FMT_E_BtYUV     5
-#define BT848_COLOR_FMT_E_Y8        6
-#define BT848_COLOR_FMT_E_RGB8      7
-#define BT848_COLOR_FMT_E_YCrCb422  8
-#define BT848_COLOR_FMT_E_YCrCb411  9
-#define BT848_COLOR_FMT_E_RAW       14
-
-#define BT848_COLOR_FMT_RGB32       0x00
-#define BT848_COLOR_FMT_RGB24       0x11
-#define BT848_COLOR_FMT_RGB16       0x22
-#define BT848_COLOR_FMT_RGB15       0x33
-#define BT848_COLOR_FMT_YUY2        0x44
-#define BT848_COLOR_FMT_BtYUV       0x55
-#define BT848_COLOR_FMT_Y8          0x66
-#define BT848_COLOR_FMT_RGB8        0x77
-#define BT848_COLOR_FMT_YCrCb422    0x88
-#define BT848_COLOR_FMT_YCrCb411    0x99
-#define BT848_COLOR_FMT_RAW         0xee
-
-#define BT848_VTOTAL_LO             0xB0
-#define BT848_VTOTAL_HI             0xB4
-
-#define BT848_COLOR_CTL                0x0D8
-#define BT848_COLOR_CTL_EXT_FRMRATE    (1<<7)
-#define BT848_COLOR_CTL_COLOR_BARS     (1<<6)
-#define BT848_COLOR_CTL_RGB_DED        (1<<5)
-#define BT848_COLOR_CTL_GAMMA          (1<<4)
-#define BT848_COLOR_CTL_WSWAP_ODD      (1<<3)
-#define BT848_COLOR_CTL_WSWAP_EVEN     (1<<2)
-#define BT848_COLOR_CTL_BSWAP_ODD      (1<<1)
-#define BT848_COLOR_CTL_BSWAP_EVEN     (1<<0)
-
-#define BT848_CAP_CTL                  0x0DC
-#define BT848_CAP_CTL_DITH_FRAME       (1<<4)
-#define BT848_CAP_CTL_CAPTURE_VBI_ODD  (1<<3)
-#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2)
-#define BT848_CAP_CTL_CAPTURE_ODD      (1<<1)
-#define BT848_CAP_CTL_CAPTURE_EVEN     (1<<0)
-
-#define BT848_VBI_PACK_SIZE    0x0E0
-
-#define BT848_VBI_PACK_DEL     0x0E4
-#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc
-#define BT848_VBI_PACK_DEL_EXT_FRAME  2
-#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1
-
-
-#define BT848_INT_STAT         0x100
-#define BT848_INT_MASK         0x104
-
-#define BT848_INT_ETBF         (1<<23)
-
-#define BT848_INT_RISCS   (0xf<<28)
-#define BT848_INT_RISC_EN (1<<27)
-#define BT848_INT_RACK    (1<<25)
-#define BT848_INT_FIELD   (1<<24)
-#define BT848_INT_SCERR   (1<<19)
-#define BT848_INT_OCERR   (1<<18)
-#define BT848_INT_PABORT  (1<<17)
-#define BT848_INT_RIPERR  (1<<16)
-#define BT848_INT_PPERR   (1<<15)
-#define BT848_INT_FDSR    (1<<14)
-#define BT848_INT_FTRGT   (1<<13)
-#define BT848_INT_FBUS    (1<<12)
-#define BT848_INT_RISCI   (1<<11)
-#define BT848_INT_GPINT   (1<<9)
-#define BT848_INT_I2CDONE (1<<8)
-#define BT848_INT_VPRES   (1<<5)
-#define BT848_INT_HLOCK   (1<<4)
-#define BT848_INT_OFLOW   (1<<3)
-#define BT848_INT_HSYNC   (1<<2)
-#define BT848_INT_VSYNC   (1<<1)
-#define BT848_INT_FMTCHG  (1<<0)
-
-
-#define BT848_GPIO_DMA_CTL             0x10C
-#define BT848_GPIO_DMA_CTL_GPINTC      (1<<15)
-#define BT848_GPIO_DMA_CTL_GPINTI      (1<<14)
-#define BT848_GPIO_DMA_CTL_GPWEC       (1<<13)
-#define BT848_GPIO_DMA_CTL_GPIOMODE    (3<<11)
-#define BT848_GPIO_DMA_CTL_GPCLKMODE   (1<<10)
-#define BT848_GPIO_DMA_CTL_PLTP23_4    (0<<6)
-#define BT848_GPIO_DMA_CTL_PLTP23_8    (1<<6)
-#define BT848_GPIO_DMA_CTL_PLTP23_16   (2<<6)
-#define BT848_GPIO_DMA_CTL_PLTP23_32   (3<<6)
-#define BT848_GPIO_DMA_CTL_PLTP1_4     (0<<4)
-#define BT848_GPIO_DMA_CTL_PLTP1_8     (1<<4)
-#define BT848_GPIO_DMA_CTL_PLTP1_16    (2<<4)
-#define BT848_GPIO_DMA_CTL_PLTP1_32    (3<<4)
-#define BT848_GPIO_DMA_CTL_PKTP_4      (0<<2)
-#define BT848_GPIO_DMA_CTL_PKTP_8      (1<<2)
-#define BT848_GPIO_DMA_CTL_PKTP_16     (2<<2)
-#define BT848_GPIO_DMA_CTL_PKTP_32     (3<<2)
-#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1)
-#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0)
-
-#define BT848_I2C              0x110
-#define BT878_I2C_MODE         (1<<7)
-#define BT878_I2C_RATE         (1<<6)
-#define BT878_I2C_NOSTOP       (1<<5)
-#define BT878_I2C_NOSTART      (1<<4)
-#define BT848_I2C_DIV          (0xf<<4)
-#define BT848_I2C_SYNC         (1<<3)
-#define BT848_I2C_W3B         (1<<2)
-#define BT848_I2C_SCL          (1<<1)
-#define BT848_I2C_SDA          (1<<0)
-
-#define BT848_RISC_STRT_ADD    0x114
-#define BT848_GPIO_OUT_EN      0x118
-#define BT848_GPIO_REG_INP     0x11C
-#define BT848_RISC_COUNT       0x120
-#define BT848_GPIO_DATA        0x200
-
-
-/* Bt848 RISC commands */
-
-/* only for the SYNC RISC command */
-#define BT848_FIFO_STATUS_FM1  0x06
-#define BT848_FIFO_STATUS_FM3  0x0e
-#define BT848_FIFO_STATUS_SOL  0x02
-#define BT848_FIFO_STATUS_EOL4 0x01
-#define BT848_FIFO_STATUS_EOL3 0x0d
-#define BT848_FIFO_STATUS_EOL2 0x09
-#define BT848_FIFO_STATUS_EOL1 0x05
-#define BT848_FIFO_STATUS_VRE  0x04
-#define BT848_FIFO_STATUS_VRO  0x0c
-#define BT848_FIFO_STATUS_PXV  0x00
-
-#define BT848_RISC_RESYNC      (1<<15)
-
-/* WRITE and SKIP */
-/* disable which bytes of each DWORD */
-#define BT848_RISC_BYTE0       (1U<<12)
-#define BT848_RISC_BYTE1       (1U<<13)
-#define BT848_RISC_BYTE2       (1U<<14)
-#define BT848_RISC_BYTE3       (1U<<15)
-#define BT848_RISC_BYTE_ALL    (0x0fU<<12)
-#define BT848_RISC_BYTE_NONE   0
-/* cause RISCI */
-#define BT848_RISC_IRQ         (1U<<24)
-/* RISC command is last one in this line */
-#define BT848_RISC_EOL         (1U<<26)
-/* RISC command is first one in this line */
-#define BT848_RISC_SOL         (1U<<27)
-
-#define BT848_RISC_WRITE       (0x01U<<28)
-#define BT848_RISC_SKIP        (0x02U<<28)
-#define BT848_RISC_WRITEC      (0x05U<<28)
-#define BT848_RISC_JUMP        (0x07U<<28)
-#define BT848_RISC_SYNC        (0x08U<<28)
-
-#define BT848_RISC_WRITE123    (0x09U<<28)
-#define BT848_RISC_SKIP123     (0x0aU<<28)
-#define BT848_RISC_WRITE1S23   (0x0bU<<28)
-
-
-/* Bt848A and higher only !! */
-#define BT848_TGLB             0x080
-#define BT848_TGCTRL           0x084
-#define BT848_FCAP             0x0E8
-#define BT848_PLL_F_LO         0x0F0
-#define BT848_PLL_F_HI         0x0F4
-
-#define BT848_PLL_XCI          0x0F8
-#define BT848_PLL_X            (1<<7)
-#define BT848_PLL_C            (1<<6)
-
-#define BT848_DVSIF            0x0FC
-
-/* Bt878 register */
-
-#define BT878_DEVCTRL 0x40
-#define BT878_EN_TBFX 0x02
-#define BT878_EN_VSFX 0x04
-
-#endif
index 4d47a0a0e974c28b089baa75352fc8f2e49aec6e..af3b61d4fa7ddacd95f0ac356cf3170818f75a2c 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * bt856 - BT856A Digital Video Encoder (Rockwell Part)
  *
  * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
@@ -285,7 +285,7 @@ bt856_command (struct i2c_client *client,
 static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
new file mode 100644 (file)
index 0000000..085477c
--- /dev/null
@@ -0,0 +1,25 @@
+config VIDEO_BT848
+       tristate "BT848 Video For Linux"
+       depends on VIDEO_DEV && PCI && I2C
+       select I2C_ALGOBIT
+       select FW_LOADER
+       select VIDEO_BTCX
+       select VIDEO_BUF
+       select VIDEO_IR
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select VIDEO_MSP3400
+       ---help---
+         Support for BT848 based frame grabber/overlay boards. This includes
+         the Miro, Hauppauge and STB boards. Please read the material in
+         <file:Documentation/video4linux/bttv/> for more information.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bttv.
+
+config VIDEO_BT848_DVB
+       bool "DVB/ATSC Support for bt878 based TV cards"
+       depends on VIDEO_BT848 && DVB_CORE
+       select DVB_BT8XX
+       ---help---
+         This adds support for DVB/ATSC cards based on the BT878 chip.
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
new file mode 100644 (file)
index 0000000..94350f2
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the video capture/playback device drivers.
+#
+
+bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
+                      bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
+                      bttv-input.o
+
+obj-$(CONFIG_VIDEO_BT848) += bttv.o
+
+EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bt8xx/bt832.c b/drivers/media/video/bt8xx/bt832.c
new file mode 100644 (file)
index 0000000..a518761
--- /dev/null
@@ -0,0 +1,265 @@
+/* Driver for Bt832 CMOS Camera Video Processor
+    i2c-addresses: 0x88 or 0x8a
+
+  The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
+  via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
+  It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
+  connected to bt848/bt878 GPIO pins on this purpose.
+  (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
+
+  Supported Cards:
+  -  Pixelview Rev.4E: 0x8a
+               GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
+
+  (c) Gunther Mayer, 2002
+
+  STATUS:
+  - detect chip and hexdump
+  - reset chip and leave low power mode
+  - detect camera present
+
+  TODO:
+  - make it work (find correct setup for Bt832 and Bt878)
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+
+#include "bttv.h"
+#include "bt832.h"
+
+MODULE_LICENSE("GPL");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { I2C_ADDR_BT832_ALT1>>1, I2C_ADDR_BT832_ALT2>>1,
+                                      I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
+
+int debug;    /* debug output */
+module_param(debug,            int, 0644);
+
+/* ---------------------------------------------------------------------- */
+
+static int bt832_detach(struct i2c_client *client);
+
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+struct bt832 {
+       struct i2c_client client;
+};
+
+int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
+{
+       int i,rc;
+       buf[0]=0x80; // start at register 0 with auto-increment
+       if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
+
+       for(i=0;i<65;i++)
+               buf[i]=0;
+       if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
+
+       // Note: On READ the first byte is the current index
+       //  (e.g. 0x80, what we just wrote)
+
+       if(debug>1) {
+               int i;
+               v4l_dbg(2, debug,i2c_client_s,"hexdump:");
+               for(i=1;i<65;i++) {
+                       if(i!=1) {
+                               if(((i-1)%8)==0) printk(" ");
+                               if(((i-1)%16)==0) {
+                                       printk("\n");
+                                       v4l_dbg(2, debug,i2c_client_s,"hexdump:");
+                               }
+                       }
+                       printk(" %02x",buf[i]);
+               }
+               printk("\n");
+       }
+       return 0;
+}
+
+// Return: 1 (is a bt832), 0 (No bt832 here)
+int bt832_init(struct i2c_client *i2c_client_s)
+{
+       unsigned char *buf;
+       int rc;
+
+       buf=kmalloc(65,GFP_KERNEL);
+       bt832_hexdump(i2c_client_s,buf);
+
+       if(buf[0x40] != 0x31) {
+               v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
+               kfree(buf);
+               return 0;
+       }
+
+       v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
+       buf[0]=BT832_VP_STATUS; // Reg.52
+       buf[1]= 0x00;
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+
+       bt832_hexdump(i2c_client_s,buf);
+
+
+       // Leave low power mode:
+       v4l_err(i2c_client_s,"leave low power mode.\n");
+       buf[0]=BT832_CAM_SETUP0; //0x39 57
+       buf[1]=0x08;
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+
+       bt832_hexdump(i2c_client_s,buf);
+
+       v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
+       buf[0]=BT832_VP_STATUS; // Reg.52
+       buf[1]= 0x00;
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+
+       bt832_hexdump(i2c_client_s,buf);
+
+
+       // Enable Output
+       v4l_info(i2c_client_s,"Enable Output\n");
+       buf[0]=BT832_VP_CONTROL1; // Reg.40
+       buf[1]= 0x27 & (~0x01); // Default | !skip
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
+
+       bt832_hexdump(i2c_client_s,buf);
+
+
+       // for testing (even works when no camera attached)
+       v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
+       buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
+       buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+
+       v4l_info(i2c_client_s,"Camera Present: %s\n",
+               (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
+
+       bt832_hexdump(i2c_client_s,buf);
+       kfree(buf);
+       return 1;
+}
+
+
+
+static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct bt832 *t;
+
+       client_template.adapter = adap;
+       client_template.addr    = addr;
+
+       if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
+               return -ENOMEM;
+       t->client = client_template;
+       i2c_set_clientdata(&t->client, t);
+       i2c_attach_client(&t->client);
+
+       v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
+
+
+       if(! bt832_init(&t->client)) {
+               bt832_detach(&t->client);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int bt832_probe(struct i2c_adapter *adap)
+{
+       if (adap->class & I2C_CLASS_TV_ANALOG)
+               return i2c_probe(adap, &addr_data, bt832_attach);
+       return 0;
+}
+
+static int bt832_detach(struct i2c_client *client)
+{
+       struct bt832 *t = i2c_get_clientdata(client);
+
+       v4l_info(&t->client,"dettach\n");
+       i2c_detach_client(client);
+       kfree(t);
+       return 0;
+}
+
+static int
+bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+       struct bt832 *t = i2c_get_clientdata(client);
+
+       if (debug>1)
+               v4l_i2c_print_ioctl(&t->client,cmd);
+
+       switch (cmd) {
+               case BT832_HEXDUMP: {
+                       unsigned char *buf;
+                       buf=kmalloc(65,GFP_KERNEL);
+                       bt832_hexdump(&t->client,buf);
+                       kfree(buf);
+               }
+               break;
+               case BT832_REATTACH:
+                       v4l_info(&t->client,"re-attach\n");
+                       i2c_del_driver(&driver);
+                       i2c_add_driver(&driver);
+               break;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+       .driver = {
+               .name   = "bt832",
+       },
+       .id             = 0, /* FIXME */
+       .attach_adapter = bt832_probe,
+       .detach_client  = bt832_detach,
+       .command        = bt832_command,
+};
+static struct i2c_client client_template =
+{
+       .name       = "bt832",
+       .driver     = &driver,
+};
+
+
+static int __init bt832_init_module(void)
+{
+       return i2c_add_driver(&driver);
+}
+
+static void __exit bt832_cleanup_module(void)
+{
+       i2c_del_driver(&driver);
+}
+
+module_init(bt832_init_module);
+module_exit(bt832_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bt832.h b/drivers/media/video/bt8xx/bt832.h
new file mode 100644 (file)
index 0000000..1ce8fa7
--- /dev/null
@@ -0,0 +1,305 @@
+/* Bt832 CMOS Camera Video Processor (VP)
+
+ The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
+  color digital camera directly to video capture devices via an 8-bit,
+  4:2:2 YUV or YCrCb video interface.
+
+ i2c addresses: 0x88 or 0x8a
+ */
+
+/* The 64 registers: */
+
+// Input Processor
+#define BT832_OFFSET 0
+#define BT832_RCOMP    1
+#define BT832_G1COMP   2
+#define BT832_G2COMP   3
+#define BT832_BCOMP    4
+// Exposures:
+#define BT832_FINEH    5
+#define BT832_FINEL    6
+#define BT832_COARSEH  7
+#define BT832_COARSEL   8
+#define BT832_CAMGAIN  9
+// Main Processor:
+#define BT832_M00      10
+#define BT832_M01      11
+#define BT832_M02      12
+#define BT832_M10      13
+#define BT832_M11      14
+#define BT832_M12      15
+#define BT832_M20      16
+#define BT832_M21      17
+#define BT832_M22      18
+#define BT832_APCOR    19
+#define BT832_GAMCOR   20
+// Level Accumulator Inputs
+#define BT832_VPCONTROL2       21
+#define BT832_ZONECODE0        22
+#define BT832_ZONECODE1        23
+#define BT832_ZONECODE2        24
+#define BT832_ZONECODE3        25
+// Level Accumulator Outputs:
+#define BT832_RACC     26
+#define BT832_GACC     27
+#define BT832_BACC     28
+#define BT832_BLACKACC 29
+#define BT832_EXP_AGC  30
+#define BT832_LACC0    31
+#define BT832_LACC1    32
+#define BT832_LACC2    33
+#define BT832_LACC3    34
+#define BT832_LACC4    35
+#define BT832_LACC5    36
+#define BT832_LACC6    37
+#define BT832_LACC7    38
+// System:
+#define BT832_VP_CONTROL0      39
+#define BT832_VP_CONTROL1      40
+#define BT832_THRESH   41
+#define BT832_VP_TESTCONTROL0  42
+#define BT832_VP_DMCODE        43
+#define BT832_ACB_CONFIG       44
+#define BT832_ACB_GNBASE       45
+#define BT832_ACB_MU   46
+#define BT832_CAM_TEST0        47
+#define BT832_AEC_CONFIG       48
+#define BT832_AEC_TL   49
+#define BT832_AEC_TC   50
+#define BT832_AEC_TH   51
+// Status:
+#define BT832_VP_STATUS        52
+#define BT832_VP_LINECOUNT     53
+#define BT832_CAM_DEVICEL      54 // e.g. 0x19
+#define BT832_CAM_DEVICEH      55 // e.g. 0x40  == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
+#define BT832_CAM_STATUS               56
+ #define BT832_56_CAMERA_PRESENT 0x20
+//Camera Setups:
+#define BT832_CAM_SETUP0       57
+#define BT832_CAM_SETUP1       58
+#define BT832_CAM_SETUP2       59
+#define BT832_CAM_SETUP3       60
+// System:
+#define BT832_DEFCOR           61
+#define BT832_VP_TESTCONTROL1  62
+#define BT832_DEVICE_ID                63
+# define BT832_DEVICE_ID__31           0x31 // Bt832 has ID 0x31
+
+/* STMicroelectronivcs VV5404 camera module
+   i2c: 0x20: sensor address
+   i2c: 0xa0: eeprom for ccd defect map
+ */
+#define VV5404_device_h                0x00  // 0x19
+#define VV5404_device_l                0x01  // 0x40
+#define VV5404_status0         0x02
+#define VV5404_linecountc      0x03 // current line counter
+#define VV5404_linecountl      0x04
+#define VV5404_setup0          0x10
+#define VV5404_setup1          0x11
+#define VV5404_setup2          0x12
+#define VV5404_setup4          0x14
+#define VV5404_setup5          0x15
+#define VV5404_fine_h          0x20  // fine exposure
+#define VV5404_fine_l          0x21
+#define VV5404_coarse_h                0x22  //coarse exposure
+#define VV5404_coarse_l                0x23
+#define VV5404_gain            0x24 // ADC pre-amp gain setting
+#define VV5404_clk_div         0x25
+#define VV5404_cr              0x76 // control register
+#define VV5404_as0             0x77 // ADC setup register
+
+
+// IOCTL
+#define BT832_HEXDUMP   _IOR('b',1,int)
+#define BT832_REATTACH _IOR('b',2,int)
+
+/* from BT8x8VXD/capdrv/dialogs.cpp */
+
+/*
+typedef enum { SVI, Logitech, Rockwell } CAMERA;
+
+static COMBOBOX_ENTRY gwCameraOptions[] =
+{
+   { SVI,      "Silicon Vision 512N" },
+   { Logitech, "Logitech VideoMan 1.3"  },
+   { Rockwell, "Rockwell QuartzSight PCI 1.0"   }
+};
+
+// SRAM table values
+//===========================================================================
+typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
+
+BYTE SRAMTable[][ 60 ] =
+{
+   // TGB_NTSC624
+   {
+      0x33, // size of table = 51
+      0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
+      0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
+      0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
+      0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
+   },
+   // TGB_NTSC780
+   {
+      0x33, // size of table = 51
+      0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
+      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
+      0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
+      0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
+   },
+   // TGB_NTSC858
+   {
+      0x33, // size of table = 51
+      0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
+      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
+      0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
+      0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
+   },
+   // TGB_NTSC392
+   // This table has been modified to be used for Fusion Rev D
+   {
+      0x2A, // size of table = 42
+      0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
+      0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
+      0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
+      0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
+      0x20, 0x00
+   }
+};
+
+//===========================================================================
+// This is the structure of the camera specifications
+//===========================================================================
+typedef struct tag_cameraSpec
+{
+   SignalFormat signal;       // which digital signal format the camera has
+   VideoFormat  vidFormat;    // video standard
+   SyncVideoRef syncRef;      // which sync video reference is used
+   State        syncOutput;   // enable sync output for sync video input?
+   DecInputClk  iClk;         // which input clock is used
+   TimeGenByte  tgb;          // which timing generator byte does the camera use
+   int          HReset;       // select 64, 48, 32, or 16 CLKx1 for HReset
+   PLLFreq      pllFreq;      // what synthesized frequency to set PLL to
+   VSIZEPARMS   vSize;        // video size the camera produces
+   int          lineCount;    // expected total number of half-line per frame - 1
+   BOOL         interlace;    // interlace signal?
+} CameraSpec;
+
+//===========================================================================
+// <UPDATE REQUIRED>
+// Camera specifications database. Update this table whenever camera spec
+// has been changed or added/deleted supported camera models
+//===========================================================================
+static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
+{  // Silicon Vision 512N
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+   {         512,           0x64,       480,    0x13,      240 },         0,       TRUE
+   },
+   // Logitech VideoMan 1.3
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+      {      640,           0x80,       480,    0x1A,      240 },         0,       TRUE
+   },
+   // Rockwell QuartzSight
+   // Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
+   //       Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+      {      352,           0x20,       576,    0x08,      288 },       607,       FALSE
+   }
+};
+*/
+
+/*
+The corresponding APIs required to be invoked are:
+SetConnector( ConCamera, TRUE/FALSE );
+SetSignalFormat( spec.signal );
+SetVideoFormat( spec.vidFormat );
+SetSyncVideoRef( spec.syncRef );
+SetEnableSyncOutput( spec.syncOutput );
+SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
+SetHReset( spec.HReset );
+SetPLL( spec.pllFreq );
+SetDecInputClock( spec.iClk );
+SetVideoInfo( spec.vSize );
+SetTotalLineCount( spec.lineCount );
+SetInterlaceMode( spec.interlace );
+*/
+
+/* from web:
+ Video Sampling
+Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
+                 Pixel Clock   Horiz    Horiz    Vert
+                  Rate         Total    Active
+NTSC square pixel  12.27 MHz    780      640      525
+NTSC CCIR-601      13.5  MHz    858      720      525
+NTSC 4FSc          14.32 MHz    910      768      525
+PAL  square pixel  14.75 MHz    944      768      625
+PAL  CCIR-601      13.5  MHz    864      720      625
+PAL  4FSc          17.72 MHz   1135      948      625
+
+For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
+*/
+
+/* from DScaler:*/
+/*
+//===========================================================================
+// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
+//
+// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
+//
+
+//===========================================================================
+// Timing generator SRAM table values for CCIR601 720x480 NTSC
+//===========================================================================
+// For NTSC CCIR656
+BYTE BtCard::SRAMTable_NTSC[] =
+{
+    // SRAM Timing Table for NTSC
+    0x0c, 0xc0, 0x00,
+    0x00, 0x90, 0xc2,
+    0x03, 0x10, 0x03,
+    0x06, 0x10, 0x34,
+    0x12, 0x12, 0x65,
+    0x02, 0x13, 0x24,
+    0x19, 0x00, 0x24,
+    0x39, 0x00, 0x96,
+    0x59, 0x08, 0x93,
+    0x83, 0x08, 0x97,
+    0x03, 0x50, 0x30,
+    0xc0, 0x40, 0x30,
+    0x86, 0x01, 0x01,
+    0xa6, 0x0d, 0x62,
+    0x03, 0x11, 0x61,
+    0x05, 0x37, 0x30,
+    0xac, 0x21, 0x50
+};
+
+//===========================================================================
+// Timing generator SRAM table values for CCIR601 720x576 NTSC
+//===========================================================================
+// For PAL CCIR656
+BYTE BtCard::SRAMTable_PAL[] =
+{
+    // SRAM Timing Table for PAL
+    0x36, 0x11, 0x01,
+    0x00, 0x90, 0x02,
+    0x05, 0x10, 0x04,
+    0x16, 0x14, 0x05,
+    0x11, 0x00, 0x04,
+    0x12, 0xc0, 0x00,
+    0x31, 0x00, 0x06,
+    0x51, 0x08, 0x03,
+    0x89, 0x08, 0x07,
+    0xc0, 0x44, 0x00,
+    0x81, 0x01, 0x01,
+    0xa9, 0x0d, 0x02,
+    0x02, 0x50, 0x03,
+    0x37, 0x3d, 0x00,
+    0xaf, 0x21, 0x00,
+};
+*/
diff --git a/drivers/media/video/bt8xx/bt848.h b/drivers/media/video/bt8xx/bt848.h
new file mode 100644 (file)
index 0000000..0bcd953
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+    bt848.h - Bt848 register offsets
+
+    Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BT848_H_
+#define _BT848_H_
+
+#ifndef PCI_VENDOR_ID_BROOKTREE
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#endif
+#ifndef PCI_DEVICE_ID_BT848
+#define PCI_DEVICE_ID_BT848     0x350
+#endif
+#ifndef PCI_DEVICE_ID_BT849
+#define PCI_DEVICE_ID_BT849     0x351
+#endif
+#ifndef PCI_DEVICE_ID_BT878
+#define PCI_DEVICE_ID_BT878     0x36e
+#endif
+#ifndef PCI_DEVICE_ID_BT879
+#define PCI_DEVICE_ID_BT879     0x36f
+#endif
+
+
+/* Brooktree 848 registers */
+
+#define BT848_DSTATUS          0x000
+#define BT848_DSTATUS_PRES     (1<<7)
+#define BT848_DSTATUS_HLOC     (1<<6)
+#define BT848_DSTATUS_FIELD    (1<<5)
+#define BT848_DSTATUS_NUML     (1<<4)
+#define BT848_DSTATUS_CSEL     (1<<3)
+#define BT848_DSTATUS_PLOCK    (1<<2)
+#define BT848_DSTATUS_LOF      (1<<1)
+#define BT848_DSTATUS_COF      (1<<0)
+
+#define BT848_IFORM            0x004
+#define BT848_IFORM_HACTIVE    (1<<7)
+#define BT848_IFORM_MUXSEL     (3<<5)
+#define BT848_IFORM_MUX0       (2<<5)
+#define BT848_IFORM_MUX1       (3<<5)
+#define BT848_IFORM_MUX2       (1<<5)
+#define BT848_IFORM_XTSEL      (3<<3)
+#define BT848_IFORM_XT0        (1<<3)
+#define BT848_IFORM_XT1        (2<<3)
+#define BT848_IFORM_XTAUTO     (3<<3)
+#define BT848_IFORM_XTBOTH     (3<<3)
+#define BT848_IFORM_NTSC       1
+#define BT848_IFORM_NTSC_J     2
+#define BT848_IFORM_PAL_BDGHI  3
+#define BT848_IFORM_PAL_M      4
+#define BT848_IFORM_PAL_N      5
+#define BT848_IFORM_SECAM      6
+#define BT848_IFORM_PAL_NC     7
+#define BT848_IFORM_AUTO       0
+#define BT848_IFORM_NORM       7
+
+#define BT848_TDEC             0x008
+#define BT848_TDEC_DEC_FIELD   (1<<7)
+#define BT848_TDEC_FLDALIGN    (1<<6)
+#define BT848_TDEC_DEC_RAT     (0x1f)
+
+#define BT848_E_CROP           0x00C
+#define BT848_O_CROP           0x08C
+
+#define BT848_E_VDELAY_LO      0x010
+#define BT848_O_VDELAY_LO      0x090
+
+#define BT848_E_VACTIVE_LO     0x014
+#define BT848_O_VACTIVE_LO     0x094
+
+#define BT848_E_HDELAY_LO      0x018
+#define BT848_O_HDELAY_LO      0x098
+
+#define BT848_E_HACTIVE_LO     0x01C
+#define BT848_O_HACTIVE_LO     0x09C
+
+#define BT848_E_HSCALE_HI      0x020
+#define BT848_O_HSCALE_HI      0x0A0
+
+#define BT848_E_HSCALE_LO      0x024
+#define BT848_O_HSCALE_LO      0x0A4
+
+#define BT848_BRIGHT           0x028
+
+#define BT848_E_CONTROL        0x02C
+#define BT848_O_CONTROL        0x0AC
+#define BT848_CONTROL_LNOTCH    (1<<7)
+#define BT848_CONTROL_COMP      (1<<6)
+#define BT848_CONTROL_LDEC      (1<<5)
+#define BT848_CONTROL_CBSENSE   (1<<4)
+#define BT848_CONTROL_CON_MSB   (1<<2)
+#define BT848_CONTROL_SAT_U_MSB (1<<1)
+#define BT848_CONTROL_SAT_V_MSB (1<<0)
+
+#define BT848_CONTRAST_LO      0x030
+#define BT848_SAT_U_LO         0x034
+#define BT848_SAT_V_LO         0x038
+#define BT848_HUE              0x03C
+
+#define BT848_E_SCLOOP         0x040
+#define BT848_O_SCLOOP         0x0C0
+#define BT848_SCLOOP_CAGC       (1<<6)
+#define BT848_SCLOOP_CKILL      (1<<5)
+#define BT848_SCLOOP_HFILT_AUTO (0<<3)
+#define BT848_SCLOOP_HFILT_CIF  (1<<3)
+#define BT848_SCLOOP_HFILT_QCIF (2<<3)
+#define BT848_SCLOOP_HFILT_ICON (3<<3)
+
+#define BT848_SCLOOP_PEAK       (1<<7)
+#define BT848_SCLOOP_HFILT_MINP (1<<3)
+#define BT848_SCLOOP_HFILT_MEDP (2<<3)
+#define BT848_SCLOOP_HFILT_MAXP (3<<3)
+
+
+#define BT848_OFORM            0x048
+#define BT848_OFORM_RANGE      (1<<7)
+#define BT848_OFORM_CORE0      (0<<5)
+#define BT848_OFORM_CORE8      (1<<5)
+#define BT848_OFORM_CORE16     (2<<5)
+#define BT848_OFORM_CORE32     (3<<5)
+
+#define BT848_E_VSCALE_HI      0x04C
+#define BT848_O_VSCALE_HI      0x0CC
+#define BT848_VSCALE_YCOMB     (1<<7)
+#define BT848_VSCALE_COMB      (1<<6)
+#define BT848_VSCALE_INT       (1<<5)
+#define BT848_VSCALE_HI        15
+
+#define BT848_E_VSCALE_LO      0x050
+#define BT848_O_VSCALE_LO      0x0D0
+#define BT848_TEST             0x054
+#define BT848_ADELAY           0x060
+#define BT848_BDELAY           0x064
+
+#define BT848_ADC              0x068
+#define BT848_ADC_RESERVED     (2<<6)
+#define BT848_ADC_SYNC_T       (1<<5)
+#define BT848_ADC_AGC_EN       (1<<4)
+#define BT848_ADC_CLK_SLEEP    (1<<3)
+#define BT848_ADC_Y_SLEEP      (1<<2)
+#define BT848_ADC_C_SLEEP      (1<<1)
+#define BT848_ADC_CRUSH        (1<<0)
+
+#define BT848_WC_UP            0x044
+#define BT848_WC_DOWN          0x078
+
+#define BT848_E_VTC            0x06C
+#define BT848_O_VTC            0x0EC
+#define BT848_VTC_HSFMT        (1<<7)
+#define BT848_VTC_VFILT_2TAP   0
+#define BT848_VTC_VFILT_3TAP   1
+#define BT848_VTC_VFILT_4TAP   2
+#define BT848_VTC_VFILT_5TAP   3
+
+#define BT848_SRESET           0x07C
+
+#define BT848_COLOR_FMT             0x0D4
+#define BT848_COLOR_FMT_O_RGB32     (0<<4)
+#define BT848_COLOR_FMT_O_RGB24     (1<<4)
+#define BT848_COLOR_FMT_O_RGB16     (2<<4)
+#define BT848_COLOR_FMT_O_RGB15     (3<<4)
+#define BT848_COLOR_FMT_O_YUY2      (4<<4)
+#define BT848_COLOR_FMT_O_BtYUV     (5<<4)
+#define BT848_COLOR_FMT_O_Y8        (6<<4)
+#define BT848_COLOR_FMT_O_RGB8      (7<<4)
+#define BT848_COLOR_FMT_O_YCrCb422  (8<<4)
+#define BT848_COLOR_FMT_O_YCrCb411  (9<<4)
+#define BT848_COLOR_FMT_O_RAW       (14<<4)
+#define BT848_COLOR_FMT_E_RGB32     0
+#define BT848_COLOR_FMT_E_RGB24     1
+#define BT848_COLOR_FMT_E_RGB16     2
+#define BT848_COLOR_FMT_E_RGB15     3
+#define BT848_COLOR_FMT_E_YUY2      4
+#define BT848_COLOR_FMT_E_BtYUV     5
+#define BT848_COLOR_FMT_E_Y8        6
+#define BT848_COLOR_FMT_E_RGB8      7
+#define BT848_COLOR_FMT_E_YCrCb422  8
+#define BT848_COLOR_FMT_E_YCrCb411  9
+#define BT848_COLOR_FMT_E_RAW       14
+
+#define BT848_COLOR_FMT_RGB32       0x00
+#define BT848_COLOR_FMT_RGB24       0x11
+#define BT848_COLOR_FMT_RGB16       0x22
+#define BT848_COLOR_FMT_RGB15       0x33
+#define BT848_COLOR_FMT_YUY2        0x44
+#define BT848_COLOR_FMT_BtYUV       0x55
+#define BT848_COLOR_FMT_Y8          0x66
+#define BT848_COLOR_FMT_RGB8        0x77
+#define BT848_COLOR_FMT_YCrCb422    0x88
+#define BT848_COLOR_FMT_YCrCb411    0x99
+#define BT848_COLOR_FMT_RAW         0xee
+
+#define BT848_VTOTAL_LO             0xB0
+#define BT848_VTOTAL_HI             0xB4
+
+#define BT848_COLOR_CTL                0x0D8
+#define BT848_COLOR_CTL_EXT_FRMRATE    (1<<7)
+#define BT848_COLOR_CTL_COLOR_BARS     (1<<6)
+#define BT848_COLOR_CTL_RGB_DED        (1<<5)
+#define BT848_COLOR_CTL_GAMMA          (1<<4)
+#define BT848_COLOR_CTL_WSWAP_ODD      (1<<3)
+#define BT848_COLOR_CTL_WSWAP_EVEN     (1<<2)
+#define BT848_COLOR_CTL_BSWAP_ODD      (1<<1)
+#define BT848_COLOR_CTL_BSWAP_EVEN     (1<<0)
+
+#define BT848_CAP_CTL                  0x0DC
+#define BT848_CAP_CTL_DITH_FRAME       (1<<4)
+#define BT848_CAP_CTL_CAPTURE_VBI_ODD  (1<<3)
+#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2)
+#define BT848_CAP_CTL_CAPTURE_ODD      (1<<1)
+#define BT848_CAP_CTL_CAPTURE_EVEN     (1<<0)
+
+#define BT848_VBI_PACK_SIZE    0x0E0
+
+#define BT848_VBI_PACK_DEL     0x0E4
+#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc
+#define BT848_VBI_PACK_DEL_EXT_FRAME  2
+#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1
+
+
+#define BT848_INT_STAT         0x100
+#define BT848_INT_MASK         0x104
+
+#define BT848_INT_ETBF         (1<<23)
+
+#define BT848_INT_RISCS   (0xf<<28)
+#define BT848_INT_RISC_EN (1<<27)
+#define BT848_INT_RACK    (1<<25)
+#define BT848_INT_FIELD   (1<<24)
+#define BT848_INT_SCERR   (1<<19)
+#define BT848_INT_OCERR   (1<<18)
+#define BT848_INT_PABORT  (1<<17)
+#define BT848_INT_RIPERR  (1<<16)
+#define BT848_INT_PPERR   (1<<15)
+#define BT848_INT_FDSR    (1<<14)
+#define BT848_INT_FTRGT   (1<<13)
+#define BT848_INT_FBUS    (1<<12)
+#define BT848_INT_RISCI   (1<<11)
+#define BT848_INT_GPINT   (1<<9)
+#define BT848_INT_I2CDONE (1<<8)
+#define BT848_INT_VPRES   (1<<5)
+#define BT848_INT_HLOCK   (1<<4)
+#define BT848_INT_OFLOW   (1<<3)
+#define BT848_INT_HSYNC   (1<<2)
+#define BT848_INT_VSYNC   (1<<1)
+#define BT848_INT_FMTCHG  (1<<0)
+
+
+#define BT848_GPIO_DMA_CTL             0x10C
+#define BT848_GPIO_DMA_CTL_GPINTC      (1<<15)
+#define BT848_GPIO_DMA_CTL_GPINTI      (1<<14)
+#define BT848_GPIO_DMA_CTL_GPWEC       (1<<13)
+#define BT848_GPIO_DMA_CTL_GPIOMODE    (3<<11)
+#define BT848_GPIO_DMA_CTL_GPCLKMODE   (1<<10)
+#define BT848_GPIO_DMA_CTL_PLTP23_4    (0<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_8    (1<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_16   (2<<6)
+#define BT848_GPIO_DMA_CTL_PLTP23_32   (3<<6)
+#define BT848_GPIO_DMA_CTL_PLTP1_4     (0<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_8     (1<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_16    (2<<4)
+#define BT848_GPIO_DMA_CTL_PLTP1_32    (3<<4)
+#define BT848_GPIO_DMA_CTL_PKTP_4      (0<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_8      (1<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_16     (2<<2)
+#define BT848_GPIO_DMA_CTL_PKTP_32     (3<<2)
+#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1)
+#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0)
+
+#define BT848_I2C              0x110
+#define BT878_I2C_MODE         (1<<7)
+#define BT878_I2C_RATE         (1<<6)
+#define BT878_I2C_NOSTOP       (1<<5)
+#define BT878_I2C_NOSTART      (1<<4)
+#define BT848_I2C_DIV          (0xf<<4)
+#define BT848_I2C_SYNC         (1<<3)
+#define BT848_I2C_W3B         (1<<2)
+#define BT848_I2C_SCL          (1<<1)
+#define BT848_I2C_SDA          (1<<0)
+
+#define BT848_RISC_STRT_ADD    0x114
+#define BT848_GPIO_OUT_EN      0x118
+#define BT848_GPIO_REG_INP     0x11C
+#define BT848_RISC_COUNT       0x120
+#define BT848_GPIO_DATA        0x200
+
+
+/* Bt848 RISC commands */
+
+/* only for the SYNC RISC command */
+#define BT848_FIFO_STATUS_FM1  0x06
+#define BT848_FIFO_STATUS_FM3  0x0e
+#define BT848_FIFO_STATUS_SOL  0x02
+#define BT848_FIFO_STATUS_EOL4 0x01
+#define BT848_FIFO_STATUS_EOL3 0x0d
+#define BT848_FIFO_STATUS_EOL2 0x09
+#define BT848_FIFO_STATUS_EOL1 0x05
+#define BT848_FIFO_STATUS_VRE  0x04
+#define BT848_FIFO_STATUS_VRO  0x0c
+#define BT848_FIFO_STATUS_PXV  0x00
+
+#define BT848_RISC_RESYNC      (1<<15)
+
+/* WRITE and SKIP */
+/* disable which bytes of each DWORD */
+#define BT848_RISC_BYTE0       (1U<<12)
+#define BT848_RISC_BYTE1       (1U<<13)
+#define BT848_RISC_BYTE2       (1U<<14)
+#define BT848_RISC_BYTE3       (1U<<15)
+#define BT848_RISC_BYTE_ALL    (0x0fU<<12)
+#define BT848_RISC_BYTE_NONE   0
+/* cause RISCI */
+#define BT848_RISC_IRQ         (1U<<24)
+/* RISC command is last one in this line */
+#define BT848_RISC_EOL         (1U<<26)
+/* RISC command is first one in this line */
+#define BT848_RISC_SOL         (1U<<27)
+
+#define BT848_RISC_WRITE       (0x01U<<28)
+#define BT848_RISC_SKIP        (0x02U<<28)
+#define BT848_RISC_WRITEC      (0x05U<<28)
+#define BT848_RISC_JUMP        (0x07U<<28)
+#define BT848_RISC_SYNC        (0x08U<<28)
+
+#define BT848_RISC_WRITE123    (0x09U<<28)
+#define BT848_RISC_SKIP123     (0x0aU<<28)
+#define BT848_RISC_WRITE1S23   (0x0bU<<28)
+
+
+/* Bt848A and higher only !! */
+#define BT848_TGLB             0x080
+#define BT848_TGCTRL           0x084
+#define BT848_FCAP             0x0E8
+#define BT848_PLL_F_LO         0x0F0
+#define BT848_PLL_F_HI         0x0F4
+
+#define BT848_PLL_XCI          0x0F8
+#define BT848_PLL_X            (1<<7)
+#define BT848_PLL_C            (1<<6)
+
+#define BT848_DVSIF            0x0FC
+
+/* Bt878 register */
+
+#define BT878_DEVCTRL 0x40
+#define BT878_EN_TBFX 0x02
+#define BT878_EN_VSFX 0x04
+
+#endif
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
new file mode 100644 (file)
index 0000000..f209a74
--- /dev/null
@@ -0,0 +1,5078 @@
+/*
+
+    bttv-cards.c
+
+    this file has configuration informations - card-specific stuff
+    like the big tvcards array for the most part
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+
+#include <asm/io.h>
+
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <media/tvaudio.h>
+
+/* fwd decl */
+static void boot_msp34xx(struct bttv *btv, int pin);
+static void boot_bt832(struct bttv *btv);
+static void hauppauge_eeprom(struct bttv *btv);
+static void avermedia_eeprom(struct bttv *btv);
+static void osprey_eeprom(struct bttv *btv);
+static void modtec_eeprom(struct bttv *btv);
+static void init_PXC200(struct bttv *btv);
+static void init_RTV24(struct bttv *btv);
+
+static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
+static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
+static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
+                                   int set);
+static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
+                                     int set);
+static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
+static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
+static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
+static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
+static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
+static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
+static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
+static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
+static void rv605_muxsel(struct bttv *btv, unsigned int input);
+static void eagle_muxsel(struct bttv *btv, unsigned int input);
+static void xguard_muxsel(struct bttv *btv, unsigned int input);
+static void ivc120_muxsel(struct bttv *btv, unsigned int input);
+static void gvc1100_muxsel(struct bttv *btv, unsigned int input);
+
+static void PXC200_muxsel(struct bttv *btv, unsigned int input);
+
+static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input);
+static void picolo_tetra_init(struct bttv *btv);
+
+static void tibetCS16_muxsel(struct bttv *btv, unsigned int input);
+static void tibetCS16_init(struct bttv *btv);
+
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input);
+static void kodicom4400r_init(struct bttv *btv);
+
+static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
+static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
+
+static int terratec_active_radio_upgrade(struct bttv *btv);
+static int tea5757_read(struct bttv *btv);
+static int tea5757_write(struct bttv *btv, int value);
+static void identify_by_eeprom(struct bttv *btv,
+                              unsigned char eeprom_data[256]);
+static int __devinit pvr_boot(struct bttv *btv);
+
+/* config variables */
+static unsigned int triton1;
+static unsigned int vsfx;
+static unsigned int latency = UNSET;
+int no_overlay=-1;
+
+static unsigned int card[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int pll[BTTV_MAX]    = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int tuner[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int svhs[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
+static struct bttv  *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
+#ifdef MODULE
+static unsigned int autoload = 1;
+#else
+static unsigned int autoload;
+#endif
+static unsigned int gpiomask = UNSET;
+static unsigned int audioall = UNSET;
+static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
+
+/* insmod options */
+module_param(triton1,    int, 0444);
+module_param(vsfx,       int, 0444);
+module_param(no_overlay, int, 0444);
+module_param(latency,    int, 0444);
+module_param(gpiomask,   int, 0444);
+module_param(audioall,   int, 0444);
+module_param(autoload,   int, 0444);
+
+module_param_array(card,     int, NULL, 0444);
+module_param_array(pll,      int, NULL, 0444);
+module_param_array(tuner,    int, NULL, 0444);
+module_param_array(svhs,     int, NULL, 0444);
+module_param_array(remote,   int, NULL, 0444);
+module_param_array(audiomux, int, NULL, 0444);
+
+MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
+                "[enable bug compatibility for triton1 + others]");
+MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
+                "[yet another chipset flaw workaround]");
+MODULE_PARM_DESC(latency,"pci latency timer");
+MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
+MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
+MODULE_PARM_DESC(tuner,"specify installed tuner type");
+MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+               " [some VIA/SIS chipsets are known to have problem with overlay]");
+
+/* ----------------------------------------------------------------------- */
+/* list of card IDs for bt878+ cards                                       */
+
+static struct CARD {
+       unsigned id;
+       int cardnr;
+       char *name;
+} cards[] __devinitdata = {
+       { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV" },
+       { 0x39000070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+       { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
+       { 0xff000070, BTTV_BOARD_OSPREY1x0,     "Osprey-100" },
+       { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
+       { 0xff020070, BTTV_BOARD_OSPREY500,     "Osprey-500" },
+       { 0xff030070, BTTV_BOARD_OSPREY2000,    "Osprey-2000" },
+       { 0xff040070, BTTV_BOARD_OSPREY540,     "Osprey-540" },
+       { 0xff070070, BTTV_BOARD_OSPREY440,     "Osprey-440" },
+
+       { 0x00011002, BTTV_BOARD_ATI_TVWONDER,  "ATI TV Wonder" },
+       { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+       { 0x6606107d, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+       { 0x6607107d, BTTV_BOARD_WINFASTVC100,  "Leadtek WinFast VC 100" },
+       { 0x6609107d, BTTV_BOARD_WINFAST2000,   "Leadtek TV 2000 XP" },
+       { 0x263610b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+       { 0x264510b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+       { 0x402010fc, BTTV_BOARD_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+       { 0x405010fc, BTTV_BOARD_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
+       { 0x407010fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+       { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+
+       { 0x001211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
+       /* some cards ship with byteswapped IDs ... */
+       { 0x1200bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
+       { 0xff00bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
+       /* this seems to happen as well ... */
+       { 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
+
+       { 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+       { 0x3060121a, BTTV_BOARD_STB2,    "3Dfx VoodooTV 100/ STB OEM" },
+
+       { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+       { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
+       { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+       { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+       { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
+       { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
+       { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
+
+       { 0x00011461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00021461, BTTV_BOARD_AVERMEDIA98,   "AVermedia TVCapture 98" },
+       { 0x00031461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00041461, BTTV_BOARD_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+       { 0x03001461, BTTV_BOARD_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
+
+       { 0x1117153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
+       { 0x1118153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
+       { 0x1119153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
+       { 0x111a153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
+
+       { 0x1123153b, BTTV_BOARD_TERRATVRADIO,  "Terratec TV Radio+" },
+       { 0x1127153b, BTTV_BOARD_TERRATV,       "Terratec TV+ (V1.05)"    },
+       /* clashes with FlyVideo
+        *{ 0x18521852, BTTV_BOARD_TERRATV,     "Terratec TV+ (V1.10)"    }, */
+       { 0x1134153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (LR102)" },
+       { 0x1135153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
+       { 0x5018153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue" },       /* ?? */
+       { 0xff3b153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
+
+       { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+       { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+       { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+       { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+       { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+
+       { 0x1430aa00, BTTV_BOARD_PV143,         "Provideo PV143A" },
+       { 0x1431aa00, BTTV_BOARD_PV143,         "Provideo PV143B" },
+       { 0x1432aa00, BTTV_BOARD_PV143,         "Provideo PV143C" },
+       { 0x1433aa00, BTTV_BOARD_PV143,         "Provideo PV143D" },
+       { 0x1433aa03, BTTV_BOARD_PV143,         "Security Eyes" },
+
+       { 0x1460aa00, BTTV_BOARD_PV150,         "Provideo PV150A-1" },
+       { 0x1461aa01, BTTV_BOARD_PV150,         "Provideo PV150A-2" },
+       { 0x1462aa02, BTTV_BOARD_PV150,         "Provideo PV150A-3" },
+       { 0x1463aa03, BTTV_BOARD_PV150,         "Provideo PV150A-4" },
+
+       { 0x1464aa04, BTTV_BOARD_PV150,         "Provideo PV150B-1" },
+       { 0x1465aa05, BTTV_BOARD_PV150,         "Provideo PV150B-2" },
+       { 0x1466aa06, BTTV_BOARD_PV150,         "Provideo PV150B-3" },
+       { 0x1467aa07, BTTV_BOARD_PV150,         "Provideo PV150B-4" },
+
+       { 0xa132ff00, BTTV_BOARD_IVC100,        "IVC-100"  },
+       { 0xa1550000, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550001, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550002, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550003, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550100, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa1550101, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa1550102, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa1550103, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa182ff00, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff01, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff02, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff03, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff04, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff05, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff06, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff07, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff08, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff09, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0a, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0b, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0c, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0d, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0e, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0f, BTTV_BOARD_IVC120,        "IVC-120G" },
+
+       { 0x41424344, BTTV_BOARD_GRANDTEC,      "GrandTec Multi Capture" },
+       { 0x01020304, BTTV_BOARD_XGUARD,        "Grandtec Grand X-Guard" },
+
+       { 0x18501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+       { 0xa0501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+       { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+       { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+       { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+       { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
+
+       { 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
+       { 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+
+       { 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
+       { 0x217d6606, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+       { 0xfff6f6ff, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+       { 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
+       { 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
+       { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
+       { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
+       { 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
+       { 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
+
+       { 0x40111554, BTTV_BOARD_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
+       { 0x17de0a01, BTTV_BOARD_KWORLD,        "Mecer TV/FM/Video Tuner" },
+
+       { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+       { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+       { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+       { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+
+       { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
+
+       /* likely broken, vendor id doesn't match the other magic views ...
+        * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+
+       /* Duplicate PCI ID, reconfigure for this board during the eeprom read.
+       * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
+
+       /* DVB cards (using pci function .1 for mpeg data xfer) */
+       { 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
+       { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+       { 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
+       { 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
+       { 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
+       { 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
+       { 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
+       { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
+       { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
+       { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
+
+       { 0, -1, NULL }
+};
+
+/* ----------------------------------------------------------------------- */
+/* array with description for bt848 / bt878 tv/grabber cards               */
+
+struct tvcard bttv_tvcards[] = {
+       /* ---- card 0x00 ---------------------------------- */
+       [BTTV_BOARD_UNKNOWN] = {
+               .name           = " *** UNKNOWN/GENERIC *** ",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0 },
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MIRO] = {
+               .name           = "MIRO PCTV",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 2, 0, 0, 0 },
+               .gpiomute       = 10,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_HAUPPAUGE] = {
+               .name           = "Hauppauge (bt848)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 3 },
+               .gpiomute       = 4,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_STB] = {
+               .name           = "STB, Gateway P/N 6000699 (bt848)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 4, 0, 2, 3 },
+               .gpiomute       = 1,
+               .no_msp34xx     = 1,
+               .needs_tvaudio  = 1,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+
+       /* ---- card 0x04 ---------------------------------- */
+       [BTTV_BOARD_INTEL] = {
+               .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = 4,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_DIAMOND] = {
+               .name           = "Diamond DTV2000",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 0, 1, 0, 1 },
+               .gpiomute       = 3,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_AVERMEDIA] = {
+               .name           = "AVerMedia TVPhone",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomask       = 0x0f,
+               .gpiomux        = { 0x0c, 0x04, 0x08, 0x04 },
+               /*                0x04 for some cards ?? */
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = avermedia_tvphone_audio,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_MATRIX_VISION] = {
+               .name           = "MATRIX-Vision MV-Delta",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 3,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x08 ---------------------------------- */
+       [BTTV_BOARD_FLYVIDEO] = {
+               .name           = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xc00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0xc00, 0x800, 0x400 },
+               .gpiomute       = 0xc00,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TURBOTV] = {
+               .name           = "IMS/IXmicro TurboTV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 1, 1, 2, 3 },
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_HAUPPAUGE878] = {
+               .name           = "Hauppauge (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x0f, /* old: 7 */
+               .muxsel         = { 2, 0, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 3 },
+               .gpiomute       = 4,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MIROPRO] = {
+               .name           = "MIRO PCTV pro",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3014f,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x20001,0x10001, 0, 0 },
+               .gpiomute       = 10,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x0c ---------------------------------- */
+       [BTTV_BOARD_ADSTECH_TV] = {
+               .name           = "ADS Technologies Channel Surfer TV (bt848)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 13, 14, 11, 7 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_AVERMEDIA98] = {
+               .name           = "AVerMedia TVCapture 98",
+               .video_inputs   = 3,
+               .audio_inputs   = 4,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 13, 14, 11, 7 },
+               .needs_tvaudio  = 1,
+               .msp34xx_alt    = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = avermedia_tv_stereo_audio,
+               .no_gpioirq     = 1,
+       },
+       [BTTV_BOARD_VHX] = {
+               .name           = "Aimslab Video Highway Xtreme (VHX)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */
+               .gpiomute       = 4,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ZOLTRIX] = {
+               .name           = "Zoltrix TV-Max",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0, 1, 0 },
+               .gpiomute       = 10,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x10 ---------------------------------- */
+       [BTTV_BOARD_PIXVIEWPLAYTV] = {
+               .name           = "Prolink Pixelview PlayTV (bt878)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x01fe00,
+               .muxsel         = { 2, 3, 1, 1 },
+       #if 0
+               /* old */
+               .gpiomux        = { 0x01c000, 0, 0x018000, 0x014000, 0x002000 },
+       #else
+               /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+               .gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
+               .gpiomute       = 0x002000,
+       #endif
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+       },
+       [BTTV_BOARD_WINVIEW_601] = {
+               .name           = "Leadtek WinView 601",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x8300f8,
+               .muxsel         = { 2, 3, 1, 1,0 },
+               .gpiomux        = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
+               .gpiomute       = 0xcfa007,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = winview_audio,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_AVEC_INTERCAP] = {
+               .name           = "AVEC Intercapture",
+               .video_inputs   = 3,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 1, 0, 0, 0 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_LIFE_FLYKIT] = {
+               .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0x8dff00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0 },
+               .no_msp34xx     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x14 ---------------------------------- */
+       [BTTV_BOARD_CEI_RAFFLES] = {
+               .name           = "CEI Raffles Card",
+               .video_inputs   = 3,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1 },
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_CONFERENCETV] = {
+               .name           = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 2,  /* tuner, line in */
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
+               .gpiomute       = 0x1800,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_PHOEBE_TVMAS] = {
+               .name           = "Askey CPH050/ Phoebe Tv Master + FM",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xc00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 1, 0x800, 0x400 },
+               .gpiomute       = 0xc00,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MODTEC_205] = {
+               .name           = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, -1 },
+               .digital_mode   = DIGITAL_MODE_CAMERA,
+               .gpiomux        = { 0, 0, 0, 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x18 ---------------------------------- */
+       [BTTV_BOARD_MAGICTVIEW061] = {
+               .name           = "Askey CPH05X/06X (bt878) [many vendors]",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xe00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = {0x400, 0x400, 0x400, 0x400 },
+               .gpiomute       = 0xc00,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_VOBIS_BOOSTAR] = {
+               .name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1f0fff,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x20000, 0x30000, 0x10000, 0 },
+               .gpiomute       = 0x40000,
+               .needs_tvaudio  = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = terratv_audio,
+       },
+       [BTTV_BOARD_HAUPPAUG_WCAM] = {
+               .name           = "Hauppauge WinCam newer (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 0, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 3 },
+               .gpiomute       = 4,
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MAXI] = {
+               .name           = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
+               .gpiomute       = 0x1800,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_SECAM,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x1c ---------------------------------- */
+       [BTTV_BOARD_TERRATV] = {
+               .name           = "Terratec TerraTV+ Version 1.1 (bt878)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1f0fff,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x20000, 0x30000, 0x10000, 0x00000 },
+               .gpiomute       = 0x40000,
+               .needs_tvaudio  = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = terratv_audio,
+               /* GPIO wiring:
+               External 20 pin connector (for Active Radio Upgrade board)
+               gpio00: i2c-sda
+               gpio01: i2c-scl
+               gpio02: om5610-data
+               gpio03: om5610-clk
+               gpio04: om5610-wre
+               gpio05: om5610-stereo
+               gpio06: rds6588-davn
+               gpio07: Pin 7 n.c.
+               gpio08: nIOW
+               gpio09+10: nIOR, nSEL ?? (bt878)
+                       gpio09: nIOR (bt848)
+                       gpio10: nSEL (bt848)
+               Sound Routing:
+               gpio16: u2-A0 (1st 4052bt)
+               gpio17: u2-A1
+               gpio18: u2-nEN
+               gpio19: u4-A0 (2nd 4052)
+               gpio20: u4-A1
+                       u4-nEN - GND
+               Btspy:
+                       00000 : Cdrom (internal audio input)
+                       10000 : ext. Video audio input
+                       20000 : TV Mono
+                       a0000 : TV Mono/2
+               1a0000 : TV Stereo
+                       30000 : Radio
+                       40000 : Mute
+       */
+
+       },
+       [BTTV_BOARD_PXC200] = {
+               /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+               .name           = "Imagenation PXC200",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1, /* was: 4 */
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0},
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel_hook    = PXC200_muxsel,
+
+       },
+       [BTTV_BOARD_FLYVIDEO_98] = {
+               .name           = "Lifeview FlyVideo 98 LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,  /* 0x8dfe00 */
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0x0800, 0x1000, 0x1000 },
+               .gpiomute       = 0x1800,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_IPROTV] = {
+               .name           = "Formac iProTV, Formac ProTV I (bt848)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 1,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 1, 0, 0, 0 },
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x20 ---------------------------------- */
+       [BTTV_BOARD_INTEL_C_S_PCI] = {
+               .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = 4,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TERRATVALUE] = {
+               .name           = "Terratec TerraTValue Version Bt878",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xffff00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x500, 0, 0x300, 0x900 },
+               .gpiomute       = 0x900,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_WINFAST2000] = {
+               .name           = "Leadtek WinFast 2000/ WinFast 2000 XP",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
+       #if 0
+               .gpiomask       = 0xc33000,
+               .gpiomux        = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
+       #else
+               /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+               .gpiomask       = 0xb33000,
+               .gpiomux        = { 0x122000,0x1000,0x0000,0x620000 },
+               .gpiomute       = 0x800000,
+       #endif
+               /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+                       gpio23 -- hef4052:nEnable (0x800000)
+                       gpio12 -- hef4052:A1
+                       gpio13 -- hef4052:A0
+               0x0000: external audio
+               0x1000: FM
+               0x2000: TV
+               0x3000: n.c.
+               Note: There exists another variant "Winfast 2000" with tv stereo !?
+               Note: eeprom only contains FF and pci subsystem id 107d:6606
+               */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+               .tuner_type     = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = winfast2000_audio,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_CHRONOS_VS2] = {
+               .name           = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
+               .gpiomute       = 0x1800,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x24 ---------------------------------- */
+       [BTTV_BOARD_TYPHOON_TVIEW] = {
+               .name           = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
+               .gpiomute       = 0x1800,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_PXELVWPLTVPRO] = {
+               .name           = "Prolink PixelView PlayTV pro",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xff,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x21, 0x20, 0x24, 0x2c },
+               .gpiomute       = 0x29,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MAGICTVIEW063] = {
+               .name           = "Askey CPH06X TView99",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x551e00,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 0x551400, 0x551200, 0, 0 },
+               .gpiomute       = 0x551c00,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_PINNACLE] = {
+               .name           = "Pinnacle PCTV Studio/Rave",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x03000F,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 2, 0xd0001, 0, 0 },
+               .gpiomute       = 1,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x28 ---------------------------------- */
+       [BTTV_BOARD_STB2] = {
+               .name           = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 4, 0, 2, 3 },
+               .gpiomute       = 1,
+               .no_msp34xx     = 1,
+               .needs_tvaudio  = 1,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_AVPHONE98] = {
+               .name           = "AVerMedia TVPhone 98",
+               .video_inputs   = 3,
+               .audio_inputs   = 4,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 13, 4, 11, 7 },
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+               .audio_hook     = avermedia_tvphone_audio,
+       },
+       [BTTV_BOARD_PV951] = {
+               .name           = "ProVideo PV951", /* pic16c54 */
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1},
+               .gpiomux        = { 0, 0, 0, 0},
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ONAIR_TV] = {
+               .name           = "Little OnAir TV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xe00b,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
+               .gpiomute       = 0xff3ffc,
+               .no_msp34xx     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x2c ---------------------------------- */
+       [BTTV_BOARD_SIGMA_TVII_FM] = {
+               .name           = "Sigma TVII-FM",
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 1, 1, 0, 2 },
+               .gpiomute       = 3,
+               .no_msp34xx     = 1,
+               .pll            = PLL_NONE,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MATRIX_VISION2] = {
+               .name           = "MATRIX-Vision MV-Delta 2",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 3,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0 },
+               .gpiomux        = { 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ZOLTRIX_GENIE] = {
+               .name           = "Zoltrix Genie TV/FM",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xbcf03f,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 },
+               .gpiomute       = 0xbcb03f,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 21,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TERRATVRADIO] = {
+               .name           = "Terratec TV/Radio+",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x70000,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x20000, 0x30000, 0x10000, 0 },
+               .gpiomute       = 0x40000,
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .pll            = PLL_35,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+
+       /* ---- card 0x30 ---------------------------------- */
+       [BTTV_BOARD_DYNALINK] = {
+               .name           = "Askey CPH03x/ Dynalink Magic TView",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = {2,0,0,0 },
+               .gpiomute       = 1,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_GVBCTV3PCI] = {
+               .name           = "IODATA GV-BCTV3/PCI",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x010f00,
+               .muxsel         = {2, 3, 0, 0 },
+               .gpiomux        = {0x10000, 0, 0x10000, 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ALPS_TSHC6_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = gvbctv3pci_audio,
+       },
+       [BTTV_BOARD_PXELVWPLTVPAK] = {
+               .name           = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 0xAA0000,
+               .muxsel         = { 2,3,1,1,-1 },
+               .digital_mode   = DIGITAL_MODE_CAMERA,
+               .gpiomux        = { 0x20000, 0, 0x80000, 0x80000 },
+               .gpiomute       = 0xa8000,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               /* GPIO wiring: (different from Rev.4C !)
+                       GPIO17: U4.A0 (first hef4052bt)
+                       GPIO19: U4.A1
+                       GPIO20: U5.A1 (second hef4052bt)
+                       GPIO21: U4.nEN
+                       GPIO22: BT832 Reset Line
+                       GPIO23: A5,A0, U5,nEN
+               Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+               */
+       },
+       [BTTV_BOARD_EAGLE] = {
+               .name           = "Eagle Wireless Capricorn2 (bt878A)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 0, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 3 },
+               .gpiomute       = 4,
+               .pll            = PLL_28,
+               .tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x34 ---------------------------------- */
+       [BTTV_BOARD_PINNACLEPRO] = {
+               /* David Härdeman <david@2gen.com> */
+               .name           = "Pinnacle PCTV Studio Pro",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 0x03000F,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 1, 0xd0001, 0, 0 },
+               .gpiomute       = 10,
+                               /* sound path (5 sources):
+                               MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+                                       0= ext. Audio IN
+                                       1= from MUX2
+                                       2= Mono TV sound from Tuner
+                                       3= not connected
+                               MUX2 (mask 0x30000):
+                                       0,2,3= from MSP34xx
+                                       1= FM stereo Radio from Tuner */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TVIEW_RDS_FM] = {
+               /* Claas Langbehn <claas@bigfoot.com>,
+               Sven Grothklags <sven@upb.de> */
+               .name           = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1c,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0, 0x10, 8 },
+               .gpiomute       = 4,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_LIFETEC_9415] = {
+               /* Tim Röstermundt <rosterm@uni-muenster.de>
+               in de.comp.os.unix.linux.hardware:
+                       options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+                       gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+                       options tuner type=5 */
+               .name           = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x18e0,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x0000,0x0800,0x1000,0x1000 },
+               .gpiomute       = 0x18e0,
+                       /* For cards with tda9820/tda9821:
+                               0x0000: Tuner normal stereo
+                               0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+                               0x0880: Tuner A2 stereo */
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_BESTBUY_EASYTV] = {
+               /* Miguel Angel Alvarez <maacruz@navegalia.com>
+               old Easy TV BT848 version (model CPH031) */
+               .name           = "Askey CPH031/ BESTBUY Easy TV",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xF,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 2, 0, 0, 0 },
+               .gpiomute       = 10,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x38 ---------------------------------- */
+       [BTTV_BOARD_FLYVIDEO_98FM] = {
+               /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+               .name           = "Lifeview FlyVideo 98FM LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
+               .gpiomute       = 0x1800,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               /* This is the ultimate cheapo capture card
+               * just a BT848A on a small PCB!
+               * Steve Hosgood <steve@equiinet.com> */
+       [BTTV_BOARD_GRANDTEC] = {
+               .name           = "GrandTec 'Grand Video Capture' (Bt848)",
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .gpiomask       = 0,
+               .muxsel         = { 3, 1 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_35,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ASKEY_CPH060] = {
+               /* Daniel Herrington <daniel.herrington@home.com> */
+               .name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xe00,
+               .muxsel         = { 2, 3, 1, 1},
+               .gpiomux        = { 0x400, 0x400, 0x400, 0x400 },
+               .gpiomute       = 0x800,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ASKEY_CPH03X] = {
+               /* Matti Mottus <mottus@physic.ut.ee> */
+               .name           = "Askey CPH03x TV Capturer",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x03000F,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 2, 0, 0, 0 },
+               .gpiomute       = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 0,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x3c ---------------------------------- */
+       [BTTV_BOARD_MM100PCTV] = {
+               /* Philip Blundell <philb@gnu.org> */
+               .name           = "Modular Technology MM100PCTV",
+               .video_inputs   = 2,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 11,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 2, 0, 0, 1 },
+               .gpiomute       = 8,
+               .pll            = PLL_35,
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_GMV1] = {
+               /* Adrian Cox <adrian@humboldt.co.uk */
+               .name           = "AG Electronics GMV1",
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .gpiomask       = 0xF,
+               .muxsel         = { 2, 2 },
+               .gpiomux        = { },
+               .no_msp34xx     = 1,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_BESTBUY_EASYTV2] = {
+               /* Miguel Angel Alvarez <maacruz@navegalia.com>
+               new Easy TV BT878 version (model CPH061)
+               special thanks to Informatica Mieres for providing the card */
+               .name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+               .video_inputs   = 3,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xFF,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 1, 0, 4, 4 },
+               .gpiomute       = 9,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ATI_TVWONDER] = {
+               /* Lukas Gebauer <geby@volny.cz> */
+               .name           = "ATI TV-Wonder",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xf03f,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 0xbffe, 0, 0xbfff, 0 },
+               .gpiomute       = 0xbffe,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x40 ---------------------------------- */
+       [BTTV_BOARD_ATI_TVWONDERVE] = {
+               /* Lukas Gebauer <geby@volny.cz> */
+               .name           = "ATI TV-Wonder VE",
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 1,
+               .muxsel         = { 2, 3, 0, 1 },
+               .gpiomux        = { 0, 0, 1, 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_FLYVIDEO2000] = {
+               /* DeeJay <deejay@westel900.net (2000S) */
+               .name           = "Lifeview FlyVideo 2000S LR90",
+               .video_inputs   = 3,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x18e0,
+               .muxsel         = { 2, 3, 0, 1 },
+                               /* Radio changed from 1e80 to 0x800 to make
+                               FlyVideo2000S in .hu happy (gm)*/
+                               /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+               .gpiomux        = { 0x0000,0x0800,0x1000,0x1000 },
+               .gpiomute       = 0x1800,
+               .audio_hook     = fv2000s_audio,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TERRATVALUER] = {
+               .name           = "Terratec TValueRadio",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xffff00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x500, 0x500, 0x300, 0x900 },
+               .gpiomute       = 0x900,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_GVBCTV4PCI] = {
+               /* TANAKA Kei <peg00625@nifty.com> */
+               .name           = "IODATA GV-BCTV4/PCI",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x010f00,
+               .muxsel         = {2, 3, 0, 0 },
+               .gpiomux        = {0x10000, 0, 0x10000, 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = gvbctv3pci_audio,
+       },
+
+       /* ---- card 0x44 ---------------------------------- */
+       [BTTV_BOARD_VOODOOTV_FM] = {
+               .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+               /* try "insmod msp3400 simple=0" if you have
+               * sound problems with this card. */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 0x4f8a00,
+               /* 0x100000: 1=MSP enabled (0=disable again)
+               * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+               .gpiomux        = {0x947fff, 0x987fff,0x947fff,0x947fff },
+               .gpiomute       = 0x947fff,
+               /* tvtuner, radio,   external,internal, mute,  stereo
+               * tuner, Composit, SVid, Composit-on-Svid-adapter */
+               .muxsel         = { 2, 3 ,0 ,1 },
+               .tuner_type     = TUNER_MT2032,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_AIMMS] = {
+               /* Philip Blundell <pb@nexus.co.uk> */
+               .name           = "Active Imaging AIMMS",
+               .video_inputs   = 1,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .muxsel         = { 2 },
+               .gpiomask       = 0
+       },
+       [BTTV_BOARD_PV_BT878P_PLUS] = {
+               /* Tomasz Pyra <hellfire@sedez.iq.pl> */
+               .name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+               .video_inputs   = 3,
+               .audio_inputs   = 4,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */
+               .gpiomute       = 13,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 25,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               /* GPIO wiring:
+                       GPIO0: U4.A0 (hef4052bt)
+                       GPIO1: U4.A1
+                       GPIO2: U4.A1 (second hef4052bt)
+                       GPIO3: U4.nEN, U5.A0, A5.nEN
+                       GPIO8-15: vrd866b ?
+               */
+       },
+       [BTTV_BOARD_FLYVIDEO98EZ] = {
+               .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x48 ---------------------------------- */
+       [BTTV_BOARD_PV_BT878P_9B] = {
+               /* Dariusz Kowalewski <darekk@automex.pl> */
+               .name           = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3f,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x01, 0x00, 0x03, 0x03 },
+               .gpiomute       = 0x09,
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
+               .has_radio      = 1,  /* Note: not all cards have radio */
+               .has_remote     = 1,
+               /* GPIO wiring:
+                       GPIO0: A0 hef4052
+                       GPIO1: A1 hef4052
+                       GPIO3: nEN hef4052
+                       GPIO8-15: vrd866b
+                       GPIO20,22,23: R30,R29,R28
+               */
+       },
+       [BTTV_BOARD_SENSORAY311] = {
+               /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
+               /* you must jumper JP5 for the card to work */
+               .name           = "Sensoray 311",
+               .video_inputs   = 5,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 4,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_RV605] = {
+               /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+               .name           = "RemoteVision MX (RV605)",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0x00,
+               .gpiomask2      = 0x07ff,
+               .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+                               0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel_hook    = rv605_muxsel,
+       },
+       [BTTV_BOARD_POWERCLR_MTV878] = {
+               .name           = "Powercolor MTV878/ MTV878R/ MTV878F",
+               .video_inputs   = 3,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+               .muxsel         = { 2, 1, 1, },
+               .gpiomux        = { 0, 1, 2, 2 },
+               .gpiomute       = 4,
+               .needs_tvaudio  = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+
+       /* ---- card 0x4c ---------------------------------- */
+       [BTTV_BOARD_WINDVR] = {
+               /* Masaki Suzuki <masaki@btree.org> */
+               .name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x140007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 3 },
+               .gpiomute       = 4,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = windvr_audio,
+       },
+       [BTTV_BOARD_GRANDTEC_MULTI] = {
+               .name           = "GrandTec Multi Capture Card (Bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_KWORLD] = {
+               .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
+               .gpiomux        = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio!
+                                               * This card lacks external Audio In, so we mute it on Ext. & Int.
+                                               * The PCB can take a sbx1637/sbx1673, wiring unknown.
+                                               * This card lacks PCI subsystem ID, sigh.
+                                               * gpiomux =1: lower volume, 2+3: mute
+                                               * btwincap uses 0x80000/0x80003
+                                               */
+               .gpiomute       = 4,
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+               radio signal strength indicators work fine. */
+               .has_radio      = 1,
+               /* GPIO Info:
+                       GPIO0,1:   HEF4052 A0,A1
+                       GPIO2:     HEF4052 nENABLE
+                       GPIO3-7:   n.c.
+                       GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
+                       GPIO14,15: ??
+                       GPIO16-21: n.c.
+                       GPIO22,23: ??
+                       ??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+       },
+       [BTTV_BOARD_DSP_TCVIDEO] = {
+               /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+               .name           = "DSP Design TCVIDEO",
+               .video_inputs   = 4,
+               .svhs           = -1,
+               .muxsel         = { 2, 3, 1, 0 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+               /* ---- card 0x50 ---------------------------------- */
+       [BTTV_BOARD_HAUPPAUGEPVR] = {
+               .name           = "Hauppauge WinTV PVR",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 0, 1, 1 },
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+
+               .gpiomask       = 7,
+               .gpiomux        = {7},
+       },
+       [BTTV_BOARD_GVBCTV5PCI] = {
+               .name           = "IODATA GV-BCTV5/PCI",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x0f0f80,
+               .muxsel         = {2, 3, 1, 0 },
+               .gpiomux        = {0x030000, 0x010000, 0, 0 },
+               .gpiomute       = 0x020000,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_NTSC_M,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = gvbctv5pci_audio,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_OSPREY1x0] = {
+               .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+               .video_inputs   = 4,                  /* id-inputs-clock */
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 3,
+               .muxsel         = { 3, 2, 0, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY1x0_848] = {
+               .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+               .video_inputs   = 3,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+
+               /* ---- card 0x54 ---------------------------------- */
+       [BTTV_BOARD_OSPREY101_848] = {
+               .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 3, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY1x1] = {
+               .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
+               .video_inputs   = 1,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 0 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY1x1_SVID] = {
+               .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 0, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY2xx] = {
+               .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
+               .video_inputs   = 1,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 0 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+
+               /* ---- card 0x58 ---------------------------------- */
+       [BTTV_BOARD_OSPREY2x0_SVID] = {
+               .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 0, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY2x0] = {
+               .name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2, 3 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY500] = {
+               .name           = "Osprey 500",   /* 500 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2, 3 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY540] = {
+               .name           = "Osprey 540",   /* 540 */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+       #if 0 /* TODO ... */
+               .svhs           = OSPREY540_SVID_ANALOG,
+               .muxsel         = {       [OSPREY540_COMP_ANALOG] = 2,
+                                       [OSPREY540_SVID_ANALOG] = 3, },
+       #endif
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       #if 0 /* TODO ... */
+               .muxsel_hook    = osprey_540_muxsel,
+               .picture_hook   = osprey_540_set_picture,
+       #endif
+       },
+
+               /* ---- card 0x5C ---------------------------------- */
+       [BTTV_BOARD_OSPREY2000] = {
+               .name           = "Osprey 2000",  /* 2000 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2, 3 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
+       },
+       [BTTV_BOARD_IDS_EAGLE] = {
+               /* M G Berberich <berberic@forwiss.uni-passau.de> */
+               .name           = "IDS Eagle",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 0, 1, 2, 3 },
+               .muxsel_hook    = eagle_muxsel,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_PINNACLESAT] = {
+               .name           = "Pinnacle PCTV Sat",
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .svhs           = 1,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .muxsel         = { 3, 0, 1, 2 },
+               .pll            = PLL_28,
+               .no_gpioirq     = 1,
+               .has_dvb        = 1,
+       },
+       [BTTV_BOARD_FORMAC_PROTV] = {
+               .name           = "Formac ProTV II (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 2,
+               /* TV, Comp1, Composite over SVID con, SVID */
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 2, 2, 0, 0 },
+               .pll            = PLL_28,
+               .has_radio      = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       /* sound routing:
+               GPIO=0x00,0x01,0x03: mute (?)
+               0x02: both TV and radio (tuner: FM1216/I)
+               The card has onboard audio connectors labeled "cdrom" and "board",
+               not soldered here, though unknown wiring.
+               Card lacks: external audio in, pci subsystem id.
+       */
+       },
+
+               /* ---- card 0x60 ---------------------------------- */
+       [BTTV_BOARD_MACHTV] = {
+               .name           = "MachTV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1},
+               .gpiomux        = { 0, 1, 2, 3},
+               .gpiomute       = 4,
+               .needs_tvaudio  = 1,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_EURESYS_PICOLO] = {
+               .name           = "Euresys Picolo",
+               .video_inputs   = 3,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .muxsel         = { 2, 0, 1},
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_PV150] = {
+               /* Luc Van Hoeylandt <luc@e-magic.be> */
+               .name           = "ProVideo PV150", /* 0x4f */
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_AD_TVK503] = {
+               /* Hiroshi Takekawa <sian@big.or.jp> */
+               /* This card lacks subsystem ID */
+               .name           = "AD-TVK503", /* 0x63 */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x001e8007,
+               .muxsel         = { 2, 3, 1, 0 },
+               /*                  Tuner, Radio, external, internal, off,  on */
+               .gpiomux        = { 0x08,  0x0f,  0x0a,     0x08 },
+               .gpiomute       = 0x0f,
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 2,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = adtvk503_audio,
+       },
+
+               /* ---- card 0x64 ---------------------------------- */
+       [BTTV_BOARD_HERCULES_SM_TV] = {
+               .name           = "Hercules Smart TV Stereo",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               /* Notes:
+               - card lacks subsystem ID
+               - stereo variant w/ daughter board with tda9874a @0xb0
+               - Audio Routing:
+                       always from tda9874 independent of GPIO (?)
+                       external line in: unknown
+               - Other chips: em78p156elp @ 0x96 (probably IR remote control)
+                       hef4053 (instead 4052) for unknown function
+               */
+       },
+       [BTTV_BOARD_PACETV] = {
+               .name           = "Pace TV & Radio Card",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1 }, /* Tuner, CVid, SVid, CVid over SVid connector */
+               .gpiomask       = 0,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+               .pll            = PLL_28,
+               /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+               only internal line out: (4pin header) RGGL
+               Radio must be decoded by msp3410d (not routed through)*/
+               /*
+               .digital_mode   = DIGITAL_MODE_CAMERA,  todo!
+               */
+       },
+       [BTTV_BOARD_IVC200] = {
+               /* Chris Willing <chris@vislab.usyd.edu.au> */
+               .name           = "IVC-200",
+               .video_inputs   = 1,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0xdf,
+               .muxsel         = { 2 },
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_XGUARD] = {
+               .name           = "Grand X-Guard / Trust 814PCI",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .tuner_type     = 4,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask2      = 0xff,
+               .muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
+               .muxsel_hook    = xguard_muxsel,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+       },
+
+               /* ---- card 0x68 ---------------------------------- */
+       [BTTV_BOARD_NEBULA_DIGITV] = {
+               .name           = "Nebula Electronics DigiTV",
+               .video_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 2, 3, 1, 0 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_dvb        = 1,
+               .has_remote     = 1,
+               .gpiomask       = 0x1b,
+               .no_gpioirq     = 1,
+       },
+       [BTTV_BOARD_PV143] = {
+               /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+               .name           = "ProVideo PV143",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VD009X1_MINIDIN] = {
+               /* M.Klahr@phytec.de */
+               .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 3,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1, 0 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VD009X1_COMBI] = {
+               .name           = "PHYTEC VD-009-X1 Combi (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 3,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+               /* ---- card 0x6c ---------------------------------- */
+       [BTTV_BOARD_VD009_MINIDIN] = {
+               .name           = "PHYTEC VD-009 MiniDIN (bt878)",
+               .video_inputs   = 10,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 9,
+               .gpiomask       = 0x00,
+               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
+                                       via the upper nibble of muxsel. here: used for
+                                       xternal video-mux */
+               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VD009_COMBI] = {
+               .name           = "PHYTEC VD-009 Combi (bt878)",
+               .video_inputs   = 10,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 9,
+               .gpiomask       = 0x00,
+               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
+                                       via the upper nibble of muxsel. here: used for
+                                       xternal video-mux */
+               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_IVC100] = {
+               .name           = "IVC-100",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0xdf,
+               .muxsel         = { 2, 3, 1, 0 },
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_IVC120] = {
+               /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+               .name           = "IVC-120G",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,    /* card has no audio */
+               .tuner          = -1,   /* card has no tuner */
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,   /* card has no svhs */
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .gpiomask       = 0x00,
+               .muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+               .muxsel_hook    = ivc120_muxsel,
+               .pll            = PLL_28,
+       },
+
+               /* ---- card 0x70 ---------------------------------- */
+       [BTTV_BOARD_PC_HDTV] = {
+               .name           = "pcHDTV HD-2000 TV",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0 },
+               .tuner_type     = TUNER_PHILIPS_ATSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_dvb        = 1,
+       },
+       [BTTV_BOARD_TWINHAN_DST] = {
+               .name           = "Twinhan DST + clones",
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_video       = 1,
+               .has_dvb        = 1,
+       },
+       [BTTV_BOARD_WINFASTVC100] = {
+               .name           = "Winfast VC100",
+               .video_inputs   = 3,
+               .audio_inputs   = 0,
+               .svhs           = 1,
+               .tuner          = -1,
+               .muxsel         = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_TEV560] = {
+               .name           = "Teppro TEV-560/InterVision IV-560",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 1, 1, 1, 1 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_35,
+       },
+
+               /* ---- card 0x74 ---------------------------------- */
+       [BTTV_BOARD_SIMUS_GVC1100] = {
+               .name           = "SIMUS GVC1100",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .muxsel         = { 2, 2, 2, 2 },
+               .gpiomask       = 0x3F,
+               .muxsel_hook    = gvc1100_muxsel,
+       },
+       [BTTV_BOARD_NGSTV_PLUS] = {
+               /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+               .name           = "NGS NGSTV+",
+               .video_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x008007,
+               .muxsel         = { 2, 3, 0, 0 },
+               .gpiomux        = { 0, 0, 0, 0 },
+               .gpiomute       = 0x000003,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_LMLBT4] = {
+               /* http://linuxmedialabs.com */
+               .name           = "LMLBT4",
+               .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 2, 3, 1, 0 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .needs_tvaudio  = 0,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TEKRAM_M205] = {
+               /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+               .name           = "Tekram M205 PRO",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = 2,
+               .needs_tvaudio  = 0,
+               .gpiomask       = 0x68,
+               .muxsel         = { 2, 3, 1 },
+               .gpiomux        = { 0x68, 0x68, 0x61, 0x61 },
+               .pll            = PLL_28,
+       },
+
+               /* ---- card 0x78 ---------------------------------- */
+       [BTTV_BOARD_CONTVFMI] = {
+               /* Javier Cendan Ares <jcendan@lycos.es> */
+               /* bt878 TV + FM without subsystem ID */
+               .name           = "Conceptronic CONTVFMi",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x008007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 2 },
+               .gpiomute       = 3,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_PICOLO_TETRA_CHIP] = {
+               /*Eric DEBIEF <debief@telemsa.com>*/
+               /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
+               /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+               /*0x79 in bttv.h*/
+               .name           = "Euresys Picolo Tetra",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .pll            = PLL_28,
+               .needs_tvaudio  = 0,
+               .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_SPIRIT_TV] = {
+               /* Spirit TV Tuner from http://spiritmodems.com.au */
+               /* Stafford Goodsell <surge@goliath.homeunix.org> */
+               .name           = "Spirit TV Tuner",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x0000000f,
+               .muxsel         = { 2, 1, 1 },
+               .gpiomux        = { 0x02, 0x00, 0x00, 0x00 },
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+       },
+       [BTTV_BOARD_AVDVBT_771] = {
+               /* Wolfram Joost <wojo@frokaschwei.de> */
+               .name           = "AVerMedia AVerTV DVB-T 771",
+               .video_inputs   = 2,
+               .svhs           = 1,
+               .tuner          = -1,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel         = { 3 , 3 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .has_dvb        = 1,
+               .no_gpioirq     = 1,
+               .has_remote     = 1,
+       },
+               /* ---- card 0x7c ---------------------------------- */
+       [BTTV_BOARD_AVDVBT_761] = {
+               /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
+               /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+               .name           = "AverMedia AverTV DVB-T 761",
+               .video_inputs   = 2,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_dvb        = 1,
+               .no_gpioirq     = 1,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_MATRIX_VISIONSQ] = {
+               /* andre.schwarz@matrix-vision.de */
+               .name             = "MATRIX Vision Sigma-SQ",
+               .video_inputs     = 16,
+               .audio_inputs     = 0,
+               .tuner            = -1,
+               .svhs             = -1,
+               .gpiomask         = 0x0,
+               .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
+                               3, 3, 3, 3, 3, 3, 3, 3 },
+               .muxsel_hook      = sigmaSQ_muxsel,
+               .gpiomux          = { 0 },
+               .no_msp34xx       = 1,
+               .pll              = PLL_28,
+               .tuner_type       = -1,
+               .tuner_addr       = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MATRIX_VISIONSLC] = {
+               /* andre.schwarz@matrix-vision.de */
+               .name             = "MATRIX Vision Sigma-SLC",
+               .video_inputs     = 4,
+               .audio_inputs     = 0,
+               .tuner            = -1,
+               .svhs             = -1,
+               .gpiomask         = 0x0,
+               .muxsel           = { 2, 2, 2, 2 },
+               .muxsel_hook      = sigmaSLC_muxsel,
+               .gpiomux          = { 0 },
+               .no_msp34xx       = 1,
+               .pll              = PLL_28,
+               .tuner_type       = -1,
+               .tuner_addr       = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               /* BTTV_BOARD_APAC_VIEWCOMP */
+       [BTTV_BOARD_APAC_VIEWCOMP] = {
+               /* Attila Kondoros <attila.kondoros@chello.hu> */
+               /* bt878 TV + FM 0x00000000 subsystem ID */
+               .name           = "APAC Viewcomp 878(AMAX)",
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 0xFF,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 2, 0, 0, 0 },
+               .gpiomute       = 10,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
+               .has_radio      = 1,   /* not every card has radio */
+       },
+
+               /* ---- card 0x80 ---------------------------------- */
+       [BTTV_BOARD_DVICO_DVBT_LITE] = {
+               /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+               .name           = "DViCO FusionHDTV DVB-T Lite",
+               .tuner          = -1,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .no_video       = 1,
+               .has_dvb        = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VGEAR_MYVCD] = {
+               /* Steven <photon38@pchome.com.tw> */
+               .name           = "V-Gear MyVCD",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3f,
+               .muxsel         = {2, 3, 1, 0 },
+               .gpiomux        = {0x31, 0x31, 0x31, 0x31 },
+               .gpiomute       = 0x31,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_NTSC_M,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 0,
+       #if 0
+               .has_remote     = 1,
+       #endif
+       },
+       [BTTV_BOARD_SUPER_TV] = {
+               /* Rick C <cryptdragoon@gmail.com> */
+               .name           = "Super TV Tuner",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0 },
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x008007,
+               .gpiomux        = { 0, 0x000001,0,0 },
+               .needs_tvaudio  = 1,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_TIBET_CS16] = {
+               /* Chris Fanning <video4linux@haydon.net> */
+               .name           = "Tibet Systems 'Progress DVR' CS16",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel_hook    = tibetCS16_muxsel,
+       },
+       [BTTV_BOARD_KODICOM_4400R] = {
+               /* Bill Brack <wbrack@mmm.com.hk> */
+               /*
+               * Note that, because of the card's wiring, the "master"
+               * BT878A chip (i.e. the one which controls the analog switch
+               * and must use this card type) is the 2nd one detected.  The
+               * other 3 chips should use card type 0x85, whose description
+               * follows this one.  There is a EEPROM on the card (which is
+               * connected to the I2C of one of those other chips), but is
+               * not currently handled.  There is also a facility for a
+               * "monitor", which is also not currently implemented.
+               */
+               .name           = "Kodicom 4400R (master)",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               /* GPIO bits 0-9 used for analog switch:
+               *   00 - 03:    camera selector
+               *   04 - 06:    channel (controller) selector
+               *   07: data (1->on, 0->off)
+               *   08: strobe
+               *   09: reset
+               * bit 16 is input from sync separator for the channel
+               */
+               .gpiomask       = 0x0003ff,
+               .no_gpioirq     = 1,
+               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda7432     = 1,
+               .no_tda9875     = 1,
+               .muxsel_hook    = kodicom4400r_muxsel,
+       },
+       [BTTV_BOARD_KODICOM_4400R_SL] = {
+               /* Bill Brack <wbrack@mmm.com.hk> */
+               /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+               * one which controls the analog switch, and must use the card type)
+               * is the 2nd one detected.  The other 3 chips should use this card
+               * type
+               */
+               .name           = "Kodicom 4400R (slave)",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0x010000,
+               .no_gpioirq     = 1,
+               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda7432     = 1,
+               .no_tda9875     = 1,
+               .muxsel_hook    = kodicom4400r_muxsel,
+       },
+               /* ---- card 0x86---------------------------------- */
+       [BTTV_BOARD_ADLINK_RTV24] = {
+               /* Michael Henson <mhenson@clarityvi.com> */
+               /* Adlink RTV24 with special unlock codes */
+               .name           = "Adlink RTV24",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0 },
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+               /* ---- card 0x87---------------------------------- */
+       [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+               /* Michael Krufky <mkrufky@m1k.net> */
+               .name           = "DViCO FusionHDTV 5 Lite",
+               .tuner          = 0,
+               .tuner_type     = TUNER_LG_TDVS_H062F,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1 },
+               .gpiomask       = 0x00e00007,
+               .gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
+               .gpiomute       = 0x00c00007,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .has_dvb        = 1,
+       },
+               /* ---- card 0x88---------------------------------- */
+       [BTTV_BOARD_ACORP_Y878F] = {
+               /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+               .name           = "Acorp Y878F",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x01fe00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x001e00, 0, 0x018000, 0x014000 },
+               .gpiomute       = 0x002000,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_YMEC_TVF66T5_B_DFF,
+               .tuner_addr     = 0xc1 >>1,
+               .radio_addr     = 0xc1 >>1,
+               .has_radio      = 1,
+       },
+               /* ---- card 0x89 ---------------------------------- */
+       [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+               .name           = "Conceptronic CTVFMi v2",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x001c0007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 2 },
+               .gpiomute       = 3,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TENA_9533_DI,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               .has_radio      = 1,
+       },
+               /* ---- card 0x8a ---------------------------------- */
+       [BTTV_BOARD_PV_BT878P_2E] = {
+               .name          = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+               .video_inputs  = 5,
+               .audio_inputs  = 1,
+               .tuner         = 0,
+               .svhs          = 3,
+               .gpiomask      = 0x01fe00,
+               .muxsel        = { 2,3,1,1,-1 },
+               .digital_mode  = DIGITAL_MODE_CAMERA,
+               .gpiomux       = { 0x00400, 0x10400, 0x04400, 0x80000 },
+               .gpiomute      = 0x12400,
+               .no_msp34xx    = 1,
+               .pll           = PLL_28,
+               .tuner_type    = TUNER_LG_PAL_FM,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote    = 1,
+       },
+               /* ---- card 0x8b ---------------------------------- */
+       [BTTV_BOARD_PV_M4900] = {
+               /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+               .name           = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3f,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0x21, 0x20, 0x24, 0x2c },
+               .gpiomute       = 0x29,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_YMEC_TVF_5533MF,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+               .has_remote     = 1,
+       },
+               /* ---- card 0x8c ---------------------------------- */
+       [BTTV_BOARD_OSPREY440]  = {
+               .name           = "Osprey 440",
+               .video_inputs   = 1,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+               /* ---- card 0x8d ---------------------------------- */
+       [BTTV_BOARD_ASOUND_SKYEYE] = {
+               .name           = "Asound Skyeye PCTV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 2, 0, 0, 0 },
+               .gpiomute       = 1,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 2,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               /* ---- card 0x8e ---------------------------------- */
+       [BTTV_BOARD_SABRENT_TVFM] = {
+               .name           = "Sabrent TV-FM (bttv version)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x108007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 100000, 100002, 100002, 100000 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TNF_5335MF,
+               .tuner_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       /* ---- card 0x8f ---------------------------------- */
+       [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
+               .name           = "Hauppauge ImpactVCB (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0x0f, /* old: 7 */
+               .muxsel         = { 0, 1, 3, 2 }, /* Composite 0-3 */
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MACHTV_MAGICTV] = {
+               /* Julian Calaby <julian.calaby@gmail.com>
+                * Slightly different from original MachTV definition (0x60)
+
+                * FIXME: RegSpy says gpiomask should be "0x001c800f", but it
+                * stuffs up remote chip. Bug is a pin on the jaecs is not set
+                * properly (methinks) causing no keyup bits being set */
+
+               .name           = "MagicTV", /* rebranded MachTV */
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },
+               .gpiomux        = { 0, 1, 2, 3 },
+               .gpiomute       = 4,
+               .tuner_type     = TUNER_TEMIC_4009FR5_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+               .has_remote     = 1,
+       },
+};
+
+static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
+
+/* ----------------------------------------------------------------------- */
+
+static unsigned char eeprom_data[256];
+
+/*
+ * identify card
+ */
+void __devinit bttv_idcard(struct bttv *btv)
+{
+       unsigned int gpiobits;
+       int i,type;
+       unsigned short tmp;
+
+       /* read PCI subsystem ID */
+       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp);
+       btv->cardid = tmp << 16;
+       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
+       btv->cardid |= tmp;
+
+       if (0 != btv->cardid && 0xffffffff != btv->cardid) {
+               /* look for the card */
+               for (type = -1, i = 0; cards[i].id != 0; i++)
+                       if (cards[i].id  == btv->cardid)
+                               type = i;
+
+               if (type != -1) {
+                       /* found it */
+                       printk(KERN_INFO "bttv%d: detected: %s [card=%d], "
+                              "PCI subsystem ID is %04x:%04x\n",
+                              btv->c.nr,cards[type].name,cards[type].cardnr,
+                              btv->cardid & 0xffff,
+                              (btv->cardid >> 16) & 0xffff);
+                       btv->c.type = cards[type].cardnr;
+               } else {
+                       /* 404 */
+                       printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
+                              btv->c.nr, btv->cardid & 0xffff,
+                              (btv->cardid >> 16) & 0xffff);
+                       printk(KERN_DEBUG "please mail id, board name and "
+                              "the correct card= insmod option to video4linux-list@redhat.com\n");
+               }
+       }
+
+       /* let the user override the autodetected type */
+       if (card[btv->c.nr] < bttv_num_tvcards)
+               btv->c.type=card[btv->c.nr];
+
+       /* print which card config we are using */
+       printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr,
+              bttv_tvcards[btv->c.type].name, btv->c.type,
+              card[btv->c.nr] < bttv_num_tvcards
+              ? "insmod option" : "autodetected");
+
+       /* overwrite gpio stuff ?? */
+       if (UNSET == audioall && UNSET == audiomux[0])
+               return;
+
+       if (UNSET != audiomux[0]) {
+               gpiobits = 0;
+               for (i = 0; i < 5; i++) {
+                       bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i];
+                       gpiobits |= audiomux[i];
+               }
+       } else {
+               gpiobits = audioall;
+               for (i = 0; i < 5; i++) {
+                       bttv_tvcards[btv->c.type].gpiomux[i] = audioall;
+               }
+       }
+       bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
+       printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
+              btv->c.nr,bttv_tvcards[btv->c.type].gpiomask);
+       for (i = 0; i < 5; i++) {
+               printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]);
+       }
+       printk("\n");
+}
+
+/*
+ * (most) board specific initialisations goes here
+ */
+
+/* Some Modular Technology cards have an eeprom, but no subsystem ID */
+static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
+{
+       int type = -1;
+
+       if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
+               type = BTTV_BOARD_MODTEC_205;
+       else if (0 == strncmp(eeprom_data+20,"Picolo",7))
+               type = BTTV_BOARD_EURESYS_PICOLO;
+       else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
+               type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
+
+       if (-1 != type) {
+               btv->c.type = type;
+               printk("bttv%d: detected by eeprom: %s [card=%d]\n",
+                      btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type);
+       }
+}
+
+static void flyvideo_gpio(struct bttv *btv)
+{
+       int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
+       int tuner=-1,ttype;
+
+       gpio_inout(0xffffff, 0);
+       udelay(8);  /* without this we would see the 0x1800 mask */
+       gpio = gpio_read();
+       /* FIXME: must restore OUR_EN ??? */
+
+       /* all cards provide GPIO info, some have an additional eeprom
+        * LR50: GPIO coding can be found lower right CP1 .. CP9
+        *       CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
+        *       GPIO14-12: n.c.
+        * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
+
+        * lowest 3 bytes are remote control codes (no handshake needed)
+        * xxxFFF: No remote control chip soldered
+        * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
+        * Note: Some bits are Audio_Mask !
+        */
+       ttype=(gpio&0x0f0000)>>16;
+       switch(ttype) {
+       case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
+               break;
+       case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+               break;
+       case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
+               break;
+       case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */
+               break;
+               case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
+               break;
+       default:
+               printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
+       }
+
+       has_remote          =   gpio & 0x800000;
+       has_radio           =   gpio & 0x400000;
+       /*   unknown                   0x200000;
+        *   unknown2                  0x100000; */
+       is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
+       has_tda9820_tda9821 = !(gpio & 0x004000);
+       is_lr90             = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
+       /*
+        * gpio & 0x001000    output bit for audio routing */
+
+       if(is_capture_only)
+               tuner=4; /* No tuner present */
+
+       printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
+              btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
+       printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
+               btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
+               is_capture_only?"yes":"no ");
+
+       if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+               btv->tuner_type = tuner;
+       btv->has_radio = has_radio;
+
+       /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
+        * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
+        * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
+       if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
+       /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
+}
+
+static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
+                              14,2,17,1, 4,1,4,3,  1,2,16,1, 4,4,4,4 };
+static int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
+                              1,1,1,1,   1,1,1,0,  0,0,0,0,  0,1,0,0 };
+
+static void miro_pinnacle_gpio(struct bttv *btv)
+{
+       int id,msp,gpio;
+       char *info;
+
+       gpio_inout(0xffffff, 0);
+       gpio = gpio_read();
+       id   = ((gpio>>10) & 63) -1;
+       msp  = bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx");
+       if (id < 32) {
+               btv->tuner_type = miro_tunermap[id];
+               if (0 == (gpio & 0x20)) {
+                       btv->has_radio = 1;
+                       if (!miro_fmtuner[id]) {
+                               btv->has_matchbox = 1;
+                               btv->mbox_we    = (1<<6);
+                               btv->mbox_most  = (1<<7);
+                               btv->mbox_clk   = (1<<8);
+                               btv->mbox_data  = (1<<9);
+                               btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+                       }
+               } else {
+                       btv->has_radio = 0;
+               }
+               if (-1 != msp) {
+                       if (btv->c.type == BTTV_BOARD_MIRO)
+                               btv->c.type = BTTV_BOARD_MIROPRO;
+                       if (btv->c.type == BTTV_BOARD_PINNACLE)
+                               btv->c.type = BTTV_BOARD_PINNACLEPRO;
+               }
+               printk(KERN_INFO
+                      "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+                      btv->c.nr, id+1, btv->tuner_type,
+                      !btv->has_radio ? "no" :
+                      (btv->has_matchbox ? "matchbox" : "fmtuner"),
+                      (-1 == msp) ? "no" : "yes");
+       } else {
+               /* new cards with microtune tuner */
+               id = 63 - id;
+               btv->has_radio = 0;
+               switch (id) {
+               case 1:
+                       info = "PAL / mono";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
+                       break;
+               case 2:
+                       info = "PAL+SECAM / stereo";
+                       btv->has_radio = 1;
+                       btv->tda9887_conf = TDA9887_QSS;
+                       break;
+               case 3:
+                       info = "NTSC / stereo";
+                       btv->has_radio = 1;
+                       btv->tda9887_conf = TDA9887_QSS;
+                       break;
+               case 4:
+                       info = "PAL+SECAM / mono";
+                       btv->tda9887_conf = TDA9887_QSS;
+                       break;
+               case 5:
+                       info = "NTSC / mono";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
+                       break;
+               case 6:
+                       info = "NTSC / stereo";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
+                       break;
+               case 7:
+                       info = "PAL / stereo";
+                       btv->tda9887_conf = TDA9887_INTERCARRIER;
+                       break;
+               default:
+                       info = "oops: unknown card";
+                       break;
+               }
+               if (-1 != msp)
+                       btv->c.type = BTTV_BOARD_PINNACLEPRO;
+               printk(KERN_INFO
+                      "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
+                      btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
+               btv->tuner_type = TUNER_MT2032;
+       }
+}
+
+/* GPIO21   L: Buffer aktiv, H: Buffer inaktiv */
+#define LM1882_SYNC_DRIVE     0x200000L
+
+static void init_ids_eagle(struct bttv *btv)
+{
+       gpio_inout(0xffffff,0xFFFF37);
+       gpio_write(0x200020);
+
+       /* flash strobe inverter ?! */
+       gpio_write(0x200024);
+
+       /* switch sync drive off */
+       gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+
+       /* set BT848 muxel to 2 */
+       btaor((2)<<5, ~(2<<5), BT848_IFORM);
+}
+
+/* Muxsel helper for the IDS Eagle.
+ * the eagles does not use the standard muxsel-bits but
+ * has its own multiplexer */
+static void eagle_muxsel(struct bttv *btv, unsigned int input)
+{
+       btaor((2)<<5, ~(3<<5), BT848_IFORM);
+       gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
+
+       /* composite */
+       /* set chroma ADC to sleep */
+       btor(BT848_ADC_C_SLEEP, BT848_ADC);
+       /* set to composite video */
+       btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+       btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+
+       /* switch sync drive off */
+       gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+}
+
+static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
+{
+       static const int masks[] = {0x30, 0x01, 0x12, 0x23};
+       gpio_write(masks[input%4]);
+}
+
+/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and
+   alarms output
+
+   GPIObit    | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+   assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1|   |   |
+
+   IN - sensor inputs, INx - sensor inputs and TI XORed together
+   O1,O2,O3 - alarm outputs (relays)
+
+   OUT ENABLE   1    1   0  . 1  1   0   0 . 0   0   0    0   = 0x6C0
+
+*/
+
+static void init_lmlbt4x(struct bttv *btv)
+{
+       printk(KERN_DEBUG "LMLBT4x init\n");
+       btwrite(0x000000, BT848_GPIO_REG_INP);
+       gpio_inout(0xffffff, 0x0006C0);
+       gpio_write(0x000000);
+}
+
+static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input)
+{
+       unsigned int inmux = input % 8;
+       gpio_inout( 0xf, 0xf );
+       gpio_bits( 0xf, inmux );
+}
+
+static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input)
+{
+       unsigned int inmux = input % 4;
+       gpio_inout( 3<<9, 3<<9 );
+       gpio_bits( 3<<9, inmux<<9 );
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void bttv_reset_audio(struct bttv *btv)
+{
+       /*
+        * BT878A has a audio-reset register.
+        * 1. This register is an audio reset function but it is in
+        *    function-0 (video capture) address space.
+        * 2. It is enough to do this once per power-up of the card.
+        * 3. There is a typo in the Conexant doc -- it is not at
+        *    0x5B, but at 0x058. (B is an odd-number, obviously a typo!).
+        * --//Shrikumar 030609
+        */
+       if (btv->id != 878)
+               return;
+
+       if (bttv_debug)
+               printk("bttv%d: BT878A ARESET\n",btv->c.nr);
+       btwrite((1<<7), 0x058);
+       udelay(10);
+       btwrite(     0, 0x058);
+}
+
+/* initialization part one -- before registering i2c bus */
+void __devinit bttv_init_card1(struct bttv *btv)
+{
+       switch (btv->c.type) {
+       case BTTV_BOARD_HAUPPAUGE:
+       case BTTV_BOARD_HAUPPAUGE878:
+               boot_msp34xx(btv,5);
+               break;
+       case BTTV_BOARD_VOODOOTV_FM:
+               boot_msp34xx(btv,20);
+               break;
+       case BTTV_BOARD_AVERMEDIA98:
+               boot_msp34xx(btv,11);
+               break;
+       case BTTV_BOARD_HAUPPAUGEPVR:
+               pvr_boot(btv);
+               break;
+       case BTTV_BOARD_TWINHAN_DST:
+       case BTTV_BOARD_AVDVBT_771:
+       case BTTV_BOARD_PINNACLESAT:
+               btv->use_i2c_hw = 1;
+               break;
+       case BTTV_BOARD_ADLINK_RTV24:
+               init_RTV24( btv );
+               break;
+
+       }
+       if (!bttv_tvcards[btv->c.type].has_dvb)
+               bttv_reset_audio(btv);
+}
+
+/* initialization part two -- after registering i2c bus */
+void __devinit bttv_init_card2(struct bttv *btv)
+{
+       int tda9887;
+       int addr=ADDR_UNSET;
+
+       btv->tuner_type = -1;
+
+       if (BTTV_BOARD_UNKNOWN == btv->c.type) {
+               bttv_readee(btv,eeprom_data,0xa0);
+               identify_by_eeprom(btv,eeprom_data);
+       }
+
+       switch (btv->c.type) {
+       case BTTV_BOARD_MIRO:
+       case BTTV_BOARD_MIROPRO:
+       case BTTV_BOARD_PINNACLE:
+       case BTTV_BOARD_PINNACLEPRO:
+               /* miro/pinnacle */
+               miro_pinnacle_gpio(btv);
+               break;
+       case BTTV_BOARD_FLYVIDEO_98:
+       case BTTV_BOARD_MAXI:
+       case BTTV_BOARD_LIFE_FLYKIT:
+       case BTTV_BOARD_FLYVIDEO:
+       case BTTV_BOARD_TYPHOON_TVIEW:
+       case BTTV_BOARD_CHRONOS_VS2:
+       case BTTV_BOARD_FLYVIDEO_98FM:
+       case BTTV_BOARD_FLYVIDEO2000:
+       case BTTV_BOARD_FLYVIDEO98EZ:
+       case BTTV_BOARD_CONFERENCETV:
+       case BTTV_BOARD_LIFETEC_9415:
+               flyvideo_gpio(btv);
+               break;
+       case BTTV_BOARD_HAUPPAUGE:
+       case BTTV_BOARD_HAUPPAUGE878:
+       case BTTV_BOARD_HAUPPAUGEPVR:
+               /* pick up some config infos from the eeprom */
+               bttv_readee(btv,eeprom_data,0xa0);
+               hauppauge_eeprom(btv);
+               break;
+       case BTTV_BOARD_AVERMEDIA98:
+       case BTTV_BOARD_AVPHONE98:
+               bttv_readee(btv,eeprom_data,0xa0);
+               avermedia_eeprom(btv);
+               break;
+       case BTTV_BOARD_PXC200:
+               init_PXC200(btv);
+               break;
+       case BTTV_BOARD_PICOLO_TETRA_CHIP:
+               picolo_tetra_init(btv);
+               break;
+       case BTTV_BOARD_VHX:
+               btv->has_radio    = 1;
+               btv->has_matchbox = 1;
+               btv->mbox_we      = 0x20;
+               btv->mbox_most    = 0;
+               btv->mbox_clk     = 0x08;
+               btv->mbox_data    = 0x10;
+               btv->mbox_mask    = 0x38;
+               break;
+       case BTTV_BOARD_VOBIS_BOOSTAR:
+       case BTTV_BOARD_TERRATV:
+               terratec_active_radio_upgrade(btv);
+               break;
+       case BTTV_BOARD_MAGICTVIEW061:
+               if (btv->cardid == 0x3002144f) {
+                       btv->has_radio=1;
+                       printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
+               }
+               break;
+       case BTTV_BOARD_STB2:
+               if (btv->cardid == 0x3060121a) {
+                       /* Fix up entry for 3DFX VoodooTV 100,
+                          which is an OEM STB card variant. */
+                       btv->has_radio=0;
+                       btv->tuner_type=TUNER_TEMIC_NTSC;
+               }
+               break;
+       case BTTV_BOARD_OSPREY1x0:
+       case BTTV_BOARD_OSPREY1x0_848:
+       case BTTV_BOARD_OSPREY101_848:
+       case BTTV_BOARD_OSPREY1x1:
+       case BTTV_BOARD_OSPREY1x1_SVID:
+       case BTTV_BOARD_OSPREY2xx:
+       case BTTV_BOARD_OSPREY2x0_SVID:
+       case BTTV_BOARD_OSPREY2x0:
+       case BTTV_BOARD_OSPREY500:
+       case BTTV_BOARD_OSPREY540:
+       case BTTV_BOARD_OSPREY2000:
+               bttv_readee(btv,eeprom_data,0xa0);
+               osprey_eeprom(btv);
+               break;
+       case BTTV_BOARD_IDS_EAGLE:
+               init_ids_eagle(btv);
+               break;
+       case BTTV_BOARD_MODTEC_205:
+               bttv_readee(btv,eeprom_data,0xa0);
+               modtec_eeprom(btv);
+               break;
+       case BTTV_BOARD_LMLBT4:
+               init_lmlbt4x(btv);
+               break;
+       case BTTV_BOARD_TIBET_CS16:
+               tibetCS16_init(btv);
+               break;
+       case BTTV_BOARD_KODICOM_4400R:
+               kodicom4400r_init(btv);
+               break;
+       }
+
+       /* pll configuration */
+       if (!(btv->id==848 && btv->revision==0x11)) {
+               /* defaults from card list */
+               if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
+                       btv->pll.pll_ifreq=28636363;
+                       btv->pll.pll_crystal=BT848_IFORM_XT0;
+               }
+               if (PLL_35 == bttv_tvcards[btv->c.type].pll) {
+                       btv->pll.pll_ifreq=35468950;
+                       btv->pll.pll_crystal=BT848_IFORM_XT1;
+               }
+               /* insmod options can override */
+               switch (pll[btv->c.nr]) {
+               case 0: /* none */
+                       btv->pll.pll_crystal = 0;
+                       btv->pll.pll_ifreq   = 0;
+                       btv->pll.pll_ofreq   = 0;
+                       break;
+               case 1: /* 28 MHz */
+               case 28:
+                       btv->pll.pll_ifreq   = 28636363;
+                       btv->pll.pll_ofreq   = 0;
+                       btv->pll.pll_crystal = BT848_IFORM_XT0;
+                       break;
+               case 2: /* 35 MHz */
+               case 35:
+                       btv->pll.pll_ifreq   = 35468950;
+                       btv->pll.pll_ofreq   = 0;
+                       btv->pll.pll_crystal = BT848_IFORM_XT1;
+                       break;
+               }
+       }
+       btv->pll.pll_current = -1;
+
+       /* tuner configuration (from card list / autodetect / insmod option) */
+       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+               addr = bttv_tvcards[btv->c.type].tuner_addr;
+
+       if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
+               if(UNSET == btv->tuner_type)
+                       btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+       if (UNSET != tuner[btv->c.nr])
+               btv->tuner_type = tuner[btv->c.nr];
+       printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+       if (btv->tuner_type != UNSET) {
+               struct tuner_setup tun_setup;
+
+               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+               tun_setup.type = btv->tuner_type;
+               tun_setup.addr = addr;
+
+               bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+       }
+
+       if (btv->tda9887_conf) {
+               bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
+                                                       &btv->tda9887_conf);
+       }
+
+       btv->svhs = bttv_tvcards[btv->c.type].svhs;
+       if (svhs[btv->c.nr] != UNSET)
+               btv->svhs = svhs[btv->c.nr];
+       if (remote[btv->c.nr] != UNSET)
+               btv->has_remote = remote[btv->c.nr];
+
+       if (bttv_tvcards[btv->c.type].has_radio)
+               btv->has_radio=1;
+       if (bttv_tvcards[btv->c.type].has_remote)
+               btv->has_remote=1;
+       if (!bttv_tvcards[btv->c.type].no_gpioirq)
+               btv->gpioirq=1;
+       if (bttv_tvcards[btv->c.type].audio_hook)
+               btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
+
+       if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
+               /* detect Bt832 chip for quartzsight digital camera */
+               if ((bttv_I2CRead(btv, I2C_ADDR_BT832_ALT1, "Bt832") >=0) ||
+                   (bttv_I2CRead(btv, I2C_ADDR_BT832_ALT2, "Bt832") >=0))
+                       boot_bt832(btv);
+       }
+
+       if (!autoload)
+               return;
+
+       /* try to detect audio/fader chips */
+       if (!bttv_tvcards[btv->c.type].no_msp34xx &&
+           bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
+               request_module("msp3400");
+
+       if (bttv_tvcards[btv->c.type].msp34xx_alt &&
+           bttv_I2CRead(btv, I2C_ADDR_MSP3400_ALT, "MSP34xx (alternate address)") >=0)
+               request_module("msp3400");
+
+       if (!bttv_tvcards[btv->c.type].no_tda9875 &&
+           bttv_I2CRead(btv, I2C_ADDR_TDA9875, "TDA9875") >=0)
+               request_module("tda9875");
+
+       if (!bttv_tvcards[btv->c.type].no_tda7432 &&
+           bttv_I2CRead(btv, I2C_ADDR_TDA7432, "TDA7432") >=0)
+               request_module("tda7432");
+
+       if (bttv_tvcards[btv->c.type].needs_tvaudio)
+               request_module("tvaudio");
+
+       /* tuner modules */
+       tda9887 = 0;
+       if (btv->tda9887_conf)
+               tda9887 = 1;
+       if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
+           bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
+               tda9887 = 1;
+       /* Hybrid DVB card, DOES have a tda9887 */
+       if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
+               tda9887 = 1;
+       if((btv->tuner_type == TUNER_PHILIPS_FM1216ME_MK3) ||
+          (btv->tuner_type == TUNER_PHILIPS_FM1236_MK3) ||
+          (btv->tuner_type == TUNER_PHILIPS_FM1256_IH3) ||
+           tda9887)
+               request_module("tda9887");
+       if (btv->tuner_type != UNSET)
+               request_module("tuner");
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static void modtec_eeprom(struct bttv *btv)
+{
+       if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
+               btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
+               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                      btv->c.nr,&eeprom_data[0x1e]);
+       } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
+               btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
+               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                      btv->c.nr,&eeprom_data[0x1e]);
+       } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+               btv->tuner_type=TUNER_PHILIPS_NTSC;
+               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                      btv->c.nr,&eeprom_data[0x1e]);
+       } else {
+               printk("bttv%d: Modtec: Unknown TunerString: %s\n",
+                      btv->c.nr,&eeprom_data[0x1e]);
+       }
+}
+
+static void __devinit hauppauge_eeprom(struct bttv *btv)
+{
+       struct tveeprom tv;
+
+       tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
+       btv->tuner_type = tv.tuner_type;
+       btv->has_radio  = tv.has_radio;
+
+       printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
+               btv->c.nr, tv.model);
+
+       /*
+        * Some of the 878 boards have duplicate PCI IDs. Switch the board
+        * type based on model #.
+        */
+       if(tv.model == 64900) {
+               printk("bttv%d: Switching board type from %s to %s\n",
+                       btv->c.nr,
+                       bttv_tvcards[btv->c.type].name,
+                       bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
+               btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
+       }
+}
+
+static int terratec_active_radio_upgrade(struct bttv *btv)
+{
+       int freq;
+
+       btv->has_radio    = 1;
+       btv->has_matchbox = 1;
+       btv->mbox_we      = 0x10;
+       btv->mbox_most    = 0x20;
+       btv->mbox_clk     = 0x08;
+       btv->mbox_data    = 0x04;
+       btv->mbox_mask    = 0x3c;
+
+       btv->mbox_iow     = 1 <<  8;
+       btv->mbox_ior     = 1 <<  9;
+       btv->mbox_csel    = 1 << 10;
+
+       freq=88000/62.5;
+       tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */
+       if (0x1ed8 == tea5757_read(btv)) {
+               printk("bttv%d: Terratec Active Radio Upgrade found.\n",
+                      btv->c.nr);
+               btv->has_radio    = 1;
+               btv->has_matchbox = 1;
+       } else {
+               btv->has_radio    = 0;
+               btv->has_matchbox = 0;
+       }
+       return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * minimal bootstrap for the WinTV/PVR -- upload altera firmware.
+ *
+ * The hcwamc.rbf firmware file is on the Hauppauge driver CD.  Have
+ * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
+ * unpacked with unzip).
+ */
+#define PVR_GPIO_DELAY         10
+
+#define BTTV_ALT_DATA          0x000001
+#define BTTV_ALT_DCLK          0x100000
+#define BTTV_ALT_NCONFIG       0x800000
+
+static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
+{
+       u32 n;
+       u8 bits;
+       int i;
+
+       gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
+       gpio_write(0);
+       udelay(PVR_GPIO_DELAY);
+
+       gpio_write(BTTV_ALT_NCONFIG);
+       udelay(PVR_GPIO_DELAY);
+
+       for (n = 0; n < microlen; n++) {
+               bits = micro[n];
+               for ( i = 0 ; i < 8 ; i++ ) {
+                       gpio_bits(BTTV_ALT_DCLK,0);
+                       if (bits & 0x01)
+                               gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA);
+                       else
+                               gpio_bits(BTTV_ALT_DATA,0);
+                       gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK);
+                       bits >>= 1;
+               }
+       }
+       gpio_bits(BTTV_ALT_DCLK,0);
+       udelay(PVR_GPIO_DELAY);
+
+       /* begin Altera init loop (Not necessary,but doesn't hurt) */
+       for (i = 0 ; i < 30 ; i++) {
+               gpio_bits(BTTV_ALT_DCLK,0);
+               gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK);
+       }
+       gpio_bits(BTTV_ALT_DCLK,0);
+       return 0;
+}
+
+static int __devinit pvr_boot(struct bttv *btv)
+{
+       const struct firmware *fw_entry;
+       int rc;
+
+       rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
+       if (rc != 0) {
+               printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
+                      btv->c.nr);
+               return rc;
+       }
+       rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
+       printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
+              btv->c.nr, (rc < 0) ? "failed" : "ok");
+       release_firmware(fw_entry);
+       return rc;
+}
+
+/* ----------------------------------------------------------------------- */
+/* some osprey specific stuff                                              */
+
+static void __devinit osprey_eeprom(struct bttv *btv)
+{
+       int i = 0;
+       unsigned char *ee = eeprom_data;
+       unsigned long serial = 0;
+
+       if (btv->c.type == 0) {
+              /* this might be an antique... check for MMAC label in eeprom */
+              if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
+                      unsigned char checksum = 0;
+                      for (i =0; i<21; i++)
+                              checksum += ee[i];
+                      if (checksum != ee[21])
+                              return;
+                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
+                      for (i = 12; i < 21; i++)
+                              serial *= 10, serial += ee[i] - '0';
+              }
+       } else {
+              unsigned short type;
+              int offset = 4*16;
+
+              for(; offset < 8*16; offset += 16) {
+                      unsigned short checksum = 0;
+                      /* verify the checksum */
+                      for(i = 0; i<14; i++) checksum += ee[i+offset];
+                              checksum = ~checksum;  /* no idea why */
+                              if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
+                                  ((checksum & 0x0FF) == ee[offset+15])) {
+                              break;
+                      }
+              }
+
+              if (offset >= 8*16)
+                      return;
+
+              /* found a valid descriptor */
+              type = (ee[offset+4]<<8) | (ee[offset+5]);
+
+              switch(type) {
+
+              /* 848 based */
+              case 0x0004:
+                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
+                      break;
+              case 0x0005:
+                      btv->c.type = BTTV_BOARD_OSPREY101_848;
+                      break;
+
+              /* 878 based */
+              case 0x0012:
+              case 0x0013:
+                      btv->c.type = BTTV_BOARD_OSPREY1x0;
+                      break;
+              case 0x0014:
+              case 0x0015:
+                      btv->c.type = BTTV_BOARD_OSPREY1x1;
+                      break;
+              case 0x0016:
+              case 0x0017:
+              case 0x0020:
+                      btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
+                      break;
+              case 0x0018:
+              case 0x0019:
+              case 0x001E:
+              case 0x001F:
+                      btv->c.type = BTTV_BOARD_OSPREY2xx;
+                      break;
+              case 0x001A:
+              case 0x001B:
+                      btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
+                      break;
+              case 0x0040:
+                      btv->c.type = BTTV_BOARD_OSPREY500;
+                      break;
+              case 0x0050:
+              case 0x0056:
+                      btv->c.type = BTTV_BOARD_OSPREY540;
+                      /* bttv_osprey_540_init(btv); */
+                      break;
+              case 0x0060:
+              case 0x0070:
+                      btv->c.type = BTTV_BOARD_OSPREY2x0;
+                      /* enable output on select control lines */
+                      gpio_inout(0xffffff,0x000303);
+                      break;
+              default:
+                      /* unknown...leave generic, but get serial # */
+                      break;
+              }
+              serial =  (ee[offset+6] << 24)
+                      | (ee[offset+7] << 16)
+                      | (ee[offset+8] <<  8)
+                      | (ee[offset+9]);
+       }
+
+       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
+             btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial);
+}
+
+/* ----------------------------------------------------------------------- */
+/* AVermedia specific stuff, from  bktr_card.c                             */
+
+static int tuner_0_table[] = {
+       TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
+       TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
+       TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+       TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+       TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
+       TUNER_PHILIPS_FM1216ME_MK3 };
+
+static int tuner_1_table[] = {
+       TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
+       TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
+       TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
+       TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
+       TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+
+static void __devinit avermedia_eeprom(struct bttv *btv)
+{
+       int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+
+       tuner_make      = (eeprom_data[0x41] & 0x7);
+       tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
+       tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
+       btv->has_remote = (eeprom_data[0x42] & 0x01);
+
+       if (tuner_make == 0 || tuner_make == 2)
+               if(tuner_format <=0x0a)
+                       tuner = tuner_0_table[tuner_format];
+       if (tuner_make == 1)
+               if(tuner_format <=9)
+                       tuner = tuner_1_table[tuner_format];
+
+       if (tuner_make == 4)
+               if(tuner_format == 0x09)
+                       tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
+
+       printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
+               btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]);
+       if(tuner) {
+               btv->tuner_type=tuner;
+               printk("%d",tuner);
+       } else
+               printk("Unknown type");
+       printk(" radio:%s remote control:%s\n",
+              tuner_tv_fm     ? "yes" : "no",
+              btv->has_remote ? "yes" : "no");
+}
+
+/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */
+void bttv_tda9880_setnorm(struct bttv *btv, int norm)
+{
+       /* fix up our card entry */
+       if(norm==VIDEO_MODE_NTSC) {
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+               dprintk("bttv_tda9880_setnorm to NTSC\n");
+       }
+       else {
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+               dprintk("bttv_tda9880_setnorm to PAL\n");
+       }
+       /* set GPIO according */
+       gpio_bits(bttv_tvcards[btv->c.type].gpiomask,
+                 bttv_tvcards[btv->c.type].gpiomux[btv->audio]);
+}
+
+
+/*
+ * reset/enable the MSP on some Hauppauge cards
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ *
+ * Hauppauge:  pin  5
+ * Voodoo:     pin 20
+ */
+static void __devinit boot_msp34xx(struct bttv *btv, int pin)
+{
+       int mask = (1 << pin);
+
+       gpio_inout(mask,mask);
+       gpio_bits(mask,0);
+       udelay(2500);
+       gpio_bits(mask,mask);
+
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"msp34xx");
+       if (bttv_verbose)
+               printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line "
+                      "init [%d]\n", btv->c.nr, pin);
+}
+
+static void __devinit boot_bt832(struct bttv *btv)
+{
+}
+
+/* ----------------------------------------------------------------------- */
+/*  Imagenation L-Model PXC200 Framegrabber */
+/*  This is basically the same procedure as
+ *  used by Alessandro Rubini in his pxc200
+ *  driver, but using BTTV functions */
+
+static void __devinit init_PXC200(struct bttv *btv)
+{
+       static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
+                                           0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                           0x00 };
+       unsigned int i;
+       int tmp;
+       u32 val;
+
+       /* Initialise GPIO-connevted stuff */
+       gpio_inout(0xffffff, (1<<13));
+       gpio_write(0);
+       udelay(3);
+       gpio_write(1<<13);
+       /* GPIO inputs are pulled up, so no need to drive
+        * reset pin any longer */
+       gpio_bits(0xffffff, 0);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"pxc200");
+
+       /*  we could/should try and reset/control the AD pots? but
+           right now  we simply  turned off the crushing.  Without
+           this the AGC drifts drifts
+           remember the EN is reverse logic -->
+           setting BT848_ADC_AGC_EN disable the AGC
+           tboult@eecs.lehigh.edu
+       */
+
+       btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
+
+       /*      Initialise MAX517 DAC */
+       printk(KERN_INFO "Setting DAC reference voltage level ...\n");
+       bttv_I2CWrite(btv,0x5E,0,0x80,1);
+
+       /*      Initialise 12C508 PIC */
+       /*      The I2CWrite and I2CRead commmands are actually to the
+        *      same chips - but the R/W bit is included in the address
+        *      argument so the numbers are different */
+
+
+       printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
+
+       /* First of all, enable the clock line. This is used in the PXC200-F */
+       val = btread(BT848_GPIO_DMA_CTL);
+       val |= BT848_GPIO_DMA_CTL_GPCLKMODE;
+       btwrite(val, BT848_GPIO_DMA_CTL);
+
+       /* Then, push to 0 the reset pin long enough to reset the *
+        * device same as above for the reset line, but not the same
+        * value sent to the GPIO-connected stuff
+        * which one is the good one? */
+       gpio_inout(0xffffff,(1<<2));
+       gpio_write(0);
+       udelay(10);
+       gpio_write(1<<2);
+
+       for (i = 0; i < ARRAY_SIZE(vals); i++) {
+               tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
+               if (tmp != -1) {
+                       printk(KERN_INFO
+                              "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
+                              vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL));
+               }
+       }
+
+       printk(KERN_INFO "PXC200 Initialised.\n");
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ *  The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock
+ *  it. This apparently involves the following procedure for each 878 chip:
+ *
+ *  1) write 0x00C3FEFF to the GPIO_OUT_EN register
+ *
+ *  2)  write to GPIO_DATA
+ *      - 0x0E
+ *      - sleep 1ms
+ *      - 0x10 + 0x0E
+ *      - sleep 10ms
+ *      - 0x0E
+ *     read from GPIO_DATA into buf (uint_32)
+ *      - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 )
+ *                 error. ERROR_CPLD_Check_Failed stop.
+ *
+ *  3) write to GPIO_DATA
+ *      - write 0x4400 + 0x0E
+ *      - sleep 10ms
+ *      - write 0x4410 + 0x0E
+ *      - sleep 1ms
+ *      - write 0x0E
+ *     read from GPIO_DATA into buf (uint_32)
+ *      - if ( buf>>18 & 0x01 ) || ( buf>>19 && 0x01 != 0 )
+ *                error. ERROR_CPLD_Check_Failed.
+ */
+/* ----------------------------------------------------------------------- */
+static void
+init_RTV24 (struct bttv *btv)
+{
+       uint32_t dataRead = 0;
+       long watchdog_value = 0x0E;
+
+       printk (KERN_INFO
+               "bttv%d: Adlink RTV-24 initialisation in progress ...\n",
+               btv->c.nr);
+
+       btwrite (0x00c3feff, BT848_GPIO_OUT_EN);
+
+       btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+       msleep (1);
+       btwrite (0x10 + watchdog_value, BT848_GPIO_DATA);
+       msleep (10);
+       btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+
+       dataRead = btread (BT848_GPIO_DATA);
+
+       if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) {
+               printk (KERN_INFO
+                       "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
+                       btv->c.nr, dataRead);
+       }
+
+       btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA);
+       msleep (10);
+       btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA);
+       msleep (1);
+       btwrite (watchdog_value, BT848_GPIO_DATA);
+       msleep (1);
+       dataRead = btread (BT848_GPIO_DATA);
+
+       if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) {
+               printk (KERN_INFO
+                       "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
+                       btv->c.nr, dataRead);
+
+               return;
+       }
+
+       printk (KERN_INFO
+               "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr);
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports     */
+/*
+ * Copyright (c) 1999 Csaba Halasz <qgehali@uni-miskolc.hu>
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
+ */
+
+static void bus_low(struct bttv *btv, int bit)
+{
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+               udelay(5);
+       }
+
+       gpio_bits(bit,0);
+       udelay(5);
+
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+               udelay(5);
+       }
+}
+
+static void bus_high(struct bttv *btv, int bit)
+{
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+               udelay(5);
+       }
+
+       gpio_bits(bit,bit);
+       udelay(5);
+
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+               udelay(5);
+       }
+}
+
+static int bus_in(struct bttv *btv, int bit)
+{
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+               udelay(5);
+
+               gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+               udelay(5);
+       }
+       return gpio_read() & (bit);
+}
+
+/* TEA5757 register bits */
+#define TEA_FREQ               0:14
+#define TEA_BUFFER             15:15
+
+#define TEA_SIGNAL_STRENGTH    16:17
+
+#define TEA_PORT1              18:18
+#define TEA_PORT0              19:19
+
+#define TEA_BAND               20:21
+#define TEA_BAND_FM            0
+#define TEA_BAND_MW            1
+#define TEA_BAND_LW            2
+#define TEA_BAND_SW            3
+
+#define TEA_MONO               22:22
+#define TEA_ALLOW_STEREO       0
+#define TEA_FORCE_MONO         1
+
+#define TEA_SEARCH_DIRECTION   23:23
+#define TEA_SEARCH_DOWN                0
+#define TEA_SEARCH_UP          1
+
+#define TEA_STATUS             24:24
+#define TEA_STATUS_TUNED       0
+#define TEA_STATUS_SEARCHING   1
+
+/* Low-level stuff */
+static int tea5757_read(struct bttv *btv)
+{
+       unsigned long timeout;
+       int value = 0;
+       int i;
+
+       /* better safe than sorry */
+       gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we);
+
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+               udelay(5);
+       }
+
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"tea5757 read");
+
+       bus_low(btv,btv->mbox_we);
+       bus_low(btv,btv->mbox_clk);
+
+       udelay(10);
+       timeout= jiffies + HZ;
+
+       /* wait for DATA line to go low; error if it doesn't */
+       while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
+               schedule();
+       if (bus_in(btv,btv->mbox_data)) {
+               printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr);
+               return -1;
+       }
+
+       dprintk("bttv%d: tea5757:",btv->c.nr);
+       for(i = 0; i < 24; i++)
+       {
+               udelay(5);
+               bus_high(btv,btv->mbox_clk);
+               udelay(5);
+               dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-');
+               bus_low(btv,btv->mbox_clk);
+               value <<= 1;
+               value |= (bus_in(btv,btv->mbox_data) == 0)?0:1;  /* MSB first */
+               dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M');
+       }
+       dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value);
+       return value;
+}
+
+static int tea5757_write(struct bttv *btv, int value)
+{
+       int i;
+       int reg = value;
+
+       gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data);
+
+       if (btv->mbox_ior) {
+               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+               udelay(5);
+       }
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"tea5757 write");
+
+       dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value);
+       bus_low(btv,btv->mbox_clk);
+       bus_high(btv,btv->mbox_we);
+       for(i = 0; i < 25; i++)
+       {
+               if (reg & 0x1000000)
+                       bus_high(btv,btv->mbox_data);
+               else
+                       bus_low(btv,btv->mbox_data);
+               reg <<= 1;
+               bus_high(btv,btv->mbox_clk);
+               udelay(10);
+               bus_low(btv,btv->mbox_clk);
+               udelay(10);
+       }
+       bus_low(btv,btv->mbox_we);  /* unmute !!! */
+       return 0;
+}
+
+void tea5757_set_freq(struct bttv *btv, unsigned short freq)
+{
+       dprintk("tea5757_set_freq %d\n",freq);
+       tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* winview                                                                 */
+
+static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+       int bits_out, loops, vol, data;
+
+       if (!set) {
+               /* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
+               v->flags |= VIDEO_AUDIO_VOLUME;
+               return;
+       }
+
+       /* 32 levels logarithmic */
+       vol = 32 - ((v->volume>>11));
+       /* units */
+       bits_out = (PT2254_DBS_IN_2>>(vol%5));
+       /* tens */
+       bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+       bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
+       data = gpio_read();
+       data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+                 WINVIEW_PT2254_STROBE);
+       for (loops = 17; loops >= 0 ; loops--) {
+               if (bits_out & (1<<loops))
+                       data |=  WINVIEW_PT2254_DATA;
+               else
+                       data &= ~WINVIEW_PT2254_DATA;
+               gpio_write(data);
+               udelay(5);
+               data |= WINVIEW_PT2254_CLK;
+               gpio_write(data);
+               udelay(5);
+               data &= ~WINVIEW_PT2254_CLK;
+               gpio_write(data);
+       }
+       data |=  WINVIEW_PT2254_STROBE;
+       data &= ~WINVIEW_PT2254_DATA;
+       gpio_write(data);
+       udelay(10);
+       data &= ~WINVIEW_PT2254_STROBE;
+       gpio_write(data);
+}
+
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but    */
+/* connect something to the GPIO pins                                      */
+
+static void
+gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int con = 0;
+
+       if (set) {
+               gpio_inout(0x300, 0x300);
+               if (v->mode & VIDEO_SOUND_LANG1)
+                       con = 0x000;
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       con = 0x300;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       con = 0x200;
+/*             if (v->mode & VIDEO_SOUND_MONO)
+ *                     con = 0x100; */
+               gpio_bits(0x300, con);
+       } else {
+               v->mode = VIDEO_SOUND_STEREO |
+                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
+       }
+}
+
+static void
+gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int val, con;
+
+       if (btv->radio_user)
+               return;
+
+       val = gpio_read();
+       if (set) {
+               con = 0x000;
+               if (v->mode & VIDEO_SOUND_LANG2) {
+                       if (v->mode & VIDEO_SOUND_LANG1) {
+                               /* LANG1 + LANG2 */
+                               con = 0x100;
+                       }
+                       else {
+                               /* LANG2 */
+                               con = 0x300;
+                       }
+               }
+               if (con != (val & 0x300)) {
+                       gpio_bits(0x300, con);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"gvbctv5pci");
+               }
+       } else {
+               switch (val & 0x70) {
+                 case 0x10:
+                       v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+                       break;
+                 case 0x30:
+                       v->mode = VIDEO_SOUND_LANG2;
+                       break;
+                 case 0x50:
+                       v->mode = VIDEO_SOUND_LANG1;
+                       break;
+                 case 0x60:
+                       v->mode = VIDEO_SOUND_STEREO;
+                       break;
+                 case 0x70:
+                       v->mode = VIDEO_SOUND_MONO;
+                       break;
+                 default:
+                       v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                                 VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+               }
+       }
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ *  0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ *  input/output sound connection, so both must be set for output mode.
+ *
+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
+ * handles this with a tda9840
+ *
+ */
+static void
+avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       int val = 0;
+
+       if (set) {
+               if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
+                       val = 0x02;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       val = 0x01;
+               if (val) {
+                       gpio_bits(0x03,val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"avermedia");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1;
+               return;
+       }
+}
+
+static void
+avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       int val = 0;
+
+       if (set) {
+               if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
+                       val = 0x01;
+               if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
+                       val = 0x02;
+               btaor(val, ~0x03, BT848_GPIO_DATA);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"avermedia");
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+               return;
+       }
+}
+
+/* Lifetec 9415 handling */
+static void
+lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       int val = 0;
+
+       if (gpio_read() & 0x4000) {
+               v->mode = VIDEO_SOUND_MONO;
+               return;
+       }
+
+       if (set) {
+               if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
+                       val = 0x0080;
+               if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
+                       val = 0x0880;
+               if ((v->mode & VIDEO_SOUND_LANG1) ||
+                   (v->mode & VIDEO_SOUND_MONO))
+                       val = 0;
+               gpio_bits(0x0880, val);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"lt9415");
+       } else {
+               /* autodetect doesn't work with this card :-( */
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+               return;
+       }
+}
+
+/* TDA9821 on TerraTV+ Bt848, Bt878 */
+static void
+terratv_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int con = 0;
+
+       if (set) {
+               gpio_inout(0x180000,0x180000);
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       con = 0x080000;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       con = 0x180000;
+               gpio_bits(0x180000, con);
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"terratv");
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
+}
+
+static void
+winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned long val = 0;
+
+       if (set) {
+               /*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+               if (v->mode & VIDEO_SOUND_MONO)         /* Mono */
+                       val = 0x420000;
+               if (v->mode & VIDEO_SOUND_LANG1)        /* Mono */
+                       val = 0x420000;
+               if (v->mode & VIDEO_SOUND_LANG2)        /* SAP */
+                       val = 0x410000;
+               if (v->mode & VIDEO_SOUND_STEREO)       /* Stereo */
+                       val = 0x020000;
+               if (val) {
+                       gpio_bits(0x430000, val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"winfast2000");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+ * revision 9B has on-board TDA9874A sound decoder).
+ *
+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+ *       will mute this cards.
+ */
+static void
+pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int val = 0;
+
+       if (btv->radio_user)
+               return;
+
+       if (set) {
+               if (v->mode & VIDEO_SOUND_MONO) {
+                       val = 0x01;
+               }
+               if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
+                   || (v->mode & VIDEO_SOUND_STEREO)) {
+                       val = 0x02;
+               }
+               if (val) {
+                       gpio_bits(0x03,val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"pvbt878p9b");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for FlyVideo 2000S (with tda9874 decoder)
+ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+ */
+static void
+fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int val = 0xffff;
+
+       if (btv->radio_user)
+               return;
+       if (set) {
+               if (v->mode & VIDEO_SOUND_MONO) {
+                       val = 0x0000;
+               }
+               if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
+                   || (v->mode & VIDEO_SOUND_STEREO)) {
+                       val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
+               }
+               if (val != 0xffff) {
+                       gpio_bits(0x1800, val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"fv2000s");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
+}
+
+/*
+ * sound control for Canopus WinDVR PCI
+ * Masaki Suzuki <masaki@btree.org>
+ */
+static void
+windvr_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned long val = 0;
+
+       if (set) {
+               if (v->mode & VIDEO_SOUND_MONO)
+                       val = 0x040000;
+               if (v->mode & VIDEO_SOUND_LANG1)
+                       val = 0;
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       val = 0x100000;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       val = 0;
+               if (val) {
+                       gpio_bits(0x140000, val);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"windvr");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
+}
+
+/*
+ * sound control for AD-TVK503
+ * Hiroshi Takekawa <sian@big.or.jp>
+ */
+static void
+adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+       unsigned int con = 0xffffff;
+
+       /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
+
+       if (set) {
+               /* btor(***, BT848_GPIO_OUT_EN); */
+               if (v->mode & VIDEO_SOUND_LANG1)
+                       con = 0x00000000;
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       con = 0x00180000;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       con = 0x00000000;
+               if (v->mode & VIDEO_SOUND_MONO)
+                       con = 0x00060000;
+               if (con != 0xffffff) {
+                       gpio_bits(0x1e0000,con);
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv, "adtvk503");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
+       }
+}
+
+/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
+ *
+ * This is needed because rv605 don't use a normal multiplex, but a crosspoint
+ * switch instead (CD22M3494E). This IC can have multiple active connections
+ * between Xn (input) and Yn (output) pins. We need to clear any existing
+ * connection prior to establish a new one, pulsing the STROBE pin.
+ *
+ * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin.
+ * GPIO pins are wired as:
+ *  GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroler)
+ *  GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroler)
+ *  GPIO[7]   - DATA (xpoint)    - P1[7] (microcontroler)
+ *  GPIO[8]   -                  - P3[5] (microcontroler)
+ *  GPIO[9]   - RESET (xpoint)   - P3[6] (microcontroler)
+ *  GPIO[10]  - STROBE (xpoint)  - P3[7] (microcontroler)
+ *  GPINTR    -                  - P3[4] (microcontroler)
+ *
+ * The microcontroler is a 80C32 like. It should be possible to change xpoint
+ * configuration either directly (as we are doing) or using the microcontroler
+ * which is also wired to I2C interface. I have no further info on the
+ * microcontroler features, one would need to disassembly the firmware.
+ * note: the vendor refused to give any information on this product, all
+ *       that stuff was found using a multimeter! :)
+ */
+static void rv605_muxsel(struct bttv *btv, unsigned int input)
+{
+       /* reset all conections */
+       gpio_bits(0x200,0x200);
+       mdelay(1);
+       gpio_bits(0x200,0x000);
+       mdelay(1);
+
+       /* create a new conection */
+       gpio_bits(0x480,0x080);
+       gpio_bits(0x480,0x480);
+       mdelay(1);
+       gpio_bits(0x480,0x080);
+       mdelay(1);
+}
+
+/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning]
+ *
+ * The CS16 (available on eBay cheap) is a PCI board with four Fusion
+ * 878A chips, a PCI bridge, an Atmel microcontroller, four sync seperator
+ * chips, ten eight input analog multiplexors, a not chip and a few
+ * other components.
+ *
+ * 16 inputs on a secondary bracket are provided and can be selected
+ * from each of the four capture chips.  Two of the eight input
+ * multiplexors are used to select from any of the 16 input signals.
+ *
+ * Unsupported hardware capabilities:
+ *  . A video output monitor on the secondary bracket can be selected from
+ *    one of the 878A chips.
+ *  . Another passthrough but I haven't spent any time investigating it.
+ *  . Digital I/O (logic level connected to GPIO) is available from an
+ *    onboard header.
+ *
+ * The on chip input mux should always be set to 2.
+ * GPIO[16:19] - Video input selection
+ * GPIO[0:3]   - Video output monitor select (only available from one 878A)
+ * GPIO[?:?]   - Digital I/O.
+ *
+ * There is an ATMEL microcontroller with an 8031 core on board.  I have not
+ * determined what function (if any) it provides.  With the microcontroller
+ * and sync seperator chips a guess is that it might have to do with video
+ * switching and maybe some digital I/O.
+ */
+static void tibetCS16_muxsel(struct bttv *btv, unsigned int input)
+{
+       /* video mux */
+       gpio_bits(0x0f0000, input << 16);
+}
+
+static void tibetCS16_init(struct bttv *btv)
+{
+       /* enable gpio bits, mask obtained via btSpy */
+       gpio_inout(0xffffff, 0x0f7fff);
+       gpio_write(0x0f7fff);
+}
+
+/*
+ * The following routines for the Kodicom-4400r get a little mind-twisting.
+ * There is a "master" controller and three "slave" controllers, together
+ * an analog switch which connects any of 16 cameras to any of the BT87A's.
+ * The analog switch is controlled by the "master", but the detection order
+ * of the four BT878A chips is in an order which I just don't understand.
+ * The "master" is actually the second controller to be detected.  The
+ * logic on the board uses logical numbers for the 4 controlers, but
+ * those numbers are different from the detection sequence.  When working
+ * with the analog switch, we need to "map" from the detection sequence
+ * over to the board's logical controller number.  This mapping sequence
+ * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
+ * unit 3, the second (which is the master) is logical unit 0, etc.
+ * We need to maintain the status of the analog switch (which of the 16
+ * cameras is connected to which of the 4 controllers).  Rather than
+ * add to the bttv structure for this, we use the data reserved for
+ * the mbox (unused for this card type).
+ */
+
+/*
+ * First a routine to set the analog switch, which controls which camera
+ * is routed to which controller.  The switch comprises an X-address
+ * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
+ * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
+ * A data value (gpio bit 7) of '1' enables the switch, and '0' disables
+ * the switch.  A STROBE bit (gpio bit 8) latches the data value into the
+ * specified address.  The idea is to set the address and data, then bring
+ * STROBE high, and finally bring STROBE back to low.
+ */
+static void kodicom4400r_write(struct bttv *btv,
+                              unsigned char xaddr,
+                              unsigned char yaddr,
+                              unsigned char data) {
+       unsigned int udata;
+
+       udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf);
+       gpio_bits(0x1ff, udata);                /* write ADDR and DAT */
+       gpio_bits(0x1ff, udata | (1 << 8));     /* strobe high */
+       gpio_bits(0x1ff, udata);                /* strobe low */
+}
+
+/*
+ * Next the mux select.  Both the "master" and "slave" 'cards' (controllers)
+ * use this routine.  The routine finds the "master" for the card, maps
+ * the controller number from the detected position over to the logical
+ * number, writes the appropriate data to the analog switch, and housekeeps
+ * the local copy of the switch information.  The parameter 'input' is the
+ * requested camera number (0 - 15).
+ */
+static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
+{
+       char *sw_status;
+       int xaddr, yaddr;
+       struct bttv *mctlr;
+       static unsigned char map[4] = {3, 0, 2, 1};
+
+       mctlr = master[btv->c.nr];
+       if (mctlr == NULL) {    /* ignore if master not yet detected */
+               return;
+       }
+       yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
+       yaddr = map[yaddr];
+       sw_status = (char *)(&mctlr->mbox_we);
+       xaddr = input & 0xf;
+       /* Check if the controller/camera pair has changed, else ignore */
+       if (sw_status[yaddr] != xaddr)
+       {
+               /* "open" the old switch, "close" the new one, save the new */
+               kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
+               sw_status[yaddr] = xaddr;
+               kodicom4400r_write(mctlr, xaddr, yaddr, 1);
+       }
+}
+
+/*
+ * During initialisation, we need to reset the analog switch.  We
+ * also preset the switch to map the 4 connectors on the card to the
+ * *user's* (see above description of kodicom4400r_muxsel) channels
+ * 0 through 3
+ */
+static void kodicom4400r_init(struct bttv *btv)
+{
+       char *sw_status = (char *)(&btv->mbox_we);
+       int ix;
+
+       gpio_inout(0x0003ff, 0x0003ff);
+       gpio_write(1 << 9);     /* reset MUX */
+       gpio_write(0);
+       /* Preset camera 0 to the 4 controllers */
+       for (ix=0; ix<4; ix++) {
+               sw_status[ix] = ix;
+               kodicom4400r_write(btv, ix, ix, 1);
+       }
+       /*
+        * Since this is the "master", we need to set up the
+        * other three controller chips' pointers to this structure
+        * for later use in the muxsel routine.
+        */
+       if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3))
+           return;
+       master[btv->c.nr-1] = btv;
+       master[btv->c.nr]   = btv;
+       master[btv->c.nr+1] = btv;
+       master[btv->c.nr+2] = btv;
+}
+
+/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel
+ * video multiplexers to provide up to 16 video inputs. These
+ * multiplexers are controlled by the lower 8 GPIO pins of the
+ * bt878. The multiplexers probably Pericom PI5V331Q or similar.
+
+ * xxx0 is pin xxx of multiplexer U5,
+ * yyy1 is pin yyy of multiplexer U2
+ */
+#define ENA0    0x01
+#define ENB0    0x02
+#define ENA1    0x04
+#define ENB1    0x08
+
+#define IN10    0x10
+#define IN00    0x20
+#define IN11    0x40
+#define IN01    0x80
+
+static void xguard_muxsel(struct bttv *btv, unsigned int input)
+{
+       static const int masks[] = {
+               ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
+               ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
+               ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
+               ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
+       };
+       gpio_write(masks[input%16]);
+}
+static void picolo_tetra_init(struct bttv *btv)
+{
+       /*This is the video input redirection fonctionality : I DID NOT USED IT. */
+       btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */
+       btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A]  set to 1*/
+}
+static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
+{
+
+       dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel =>  input = %d\n",btv->c.nr,input);
+       /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/
+       /*GPIO[20]&GPIO[21] used to choose the right input*/
+       btwrite (input<<20,BT848_GPIO_DATA);
+
+}
+
+/*
+ * ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>]
+ *
+ * The IVC120G security card has 4 i2c controlled TDA8540 matrix
+ * swichers to provide 16 channels to MUX0. The TDA8540's have
+ * 4 indepedant outputs and as such the IVC120G also has the
+ * optional "Monitor Out" bus. This allows the card to be looking
+ * at one input while the monitor is looking at another.
+ *
+ * Since I've couldn't be bothered figuring out how to add an
+ * independant muxsel for the monitor bus, I've just set it to
+ * whatever the card is looking at.
+ *
+ *  OUT0 of the TDA8540's is connected to MUX0         (0x03)
+ *  OUT1 of the TDA8540's is connected to "Monitor Out"        (0x0C)
+ *
+ *  TDA8540_ALT3 IN0-3 = Channel 13 - 16       (0x03)
+ *  TDA8540_ALT4 IN0-3 = Channel 1 - 4         (0x03)
+ *  TDA8540_ALT5 IN0-3 = Channel 5 - 8         (0x03)
+ *  TDA8540_ALT6 IN0-3 = Channel 9 - 12                (0x03)
+ *
+ */
+
+/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */
+#define I2C_TDA8540        0x90
+#define I2C_TDA8540_ALT1   0x92
+#define I2C_TDA8540_ALT2   0x94
+#define I2C_TDA8540_ALT3   0x96
+#define I2C_TDA8540_ALT4   0x98
+#define I2C_TDA8540_ALT5   0x9a
+#define I2C_TDA8540_ALT6   0x9c
+
+static void ivc120_muxsel(struct bttv *btv, unsigned int input)
+{
+       /* Simple maths */
+       int key = input % 4;
+       int matrix = input / 4;
+
+       dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
+               btv->c.nr, input, matrix, key);
+
+       /* Handles the input selection on the TDA8540's */
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00,
+                     ((matrix == 3) ? (key | key << 2) : 0x00), 1);
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00,
+                     ((matrix == 0) ? (key | key << 2) : 0x00), 1);
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00,
+                     ((matrix == 1) ? (key | key << 2) : 0x00), 1);
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00,
+                     ((matrix == 2) ? (key | key << 2) : 0x00), 1);
+
+       /* Handles the output enables on the TDA8540's */
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02,
+                     ((matrix == 3) ? 0x03 : 0x00), 1);  /* 13 - 16 */
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02,
+                     ((matrix == 0) ? 0x03 : 0x00), 1);  /* 1-4 */
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02,
+                     ((matrix == 1) ? 0x03 : 0x00), 1);  /* 5-8 */
+       bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
+                     ((matrix == 2) ? 0x03 : 0x00), 1);  /* 9-12 */
+
+       /* Selects MUX0 for input on the 878 */
+       btaor((0)<<5, ~(3<<5), BT848_IFORM);
+}
+
+
+/* PXC200 muxsel helper
+ * luke@syseng.anu.edu.au
+ * another transplant
+ * from Alessandro Rubini (rubini@linux.it)
+ *
+ * There are 4 kinds of cards:
+ * PXC200L which is bt848
+ * PXC200F which is bt848 with PIC controlling mux
+ * PXC200AL which is bt878
+ * PXC200AF which is bt878 with PIC controlling mux
+ */
+#define PX_CFG_PXC200F 0x01
+#define PX_FLAG_PXC200A  0x00001000 /* a pxc200A is bt-878 based */
+#define PX_I2C_PIC       0x0f
+#define PX_PXC200A_CARDID 0x200a1295
+#define PX_I2C_CMD_CFG   0x00
+
+static void PXC200_muxsel(struct bttv *btv, unsigned int input)
+{
+       int rc;
+       long mux;
+       int bitmask;
+       unsigned char buf[2];
+
+       /* Read PIC config to determine if this is a PXC200F */
+       /* PX_I2C_CMD_CFG*/
+       buf[0]=0;
+       buf[1]=0;
+       rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1);
+       if (rc) {
+         printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc);
+         /* not PXC ? do nothing */
+         return;
+       }
+
+       rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL);
+       if (!(rc & PX_CFG_PXC200F)) {
+         printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc);
+         return;
+       }
+
+
+       /* The multiplexer in the 200F is handled by the GPIO port */
+       /* get correct mapping between inputs  */
+       /*  mux = bttv_tvcards[btv->type].muxsel[input] & 3; */
+       /* ** not needed!?   */
+       mux = input;
+
+       /* make sure output pins are enabled */
+       /* bitmask=0x30f; */
+       bitmask=0x302;
+       /* check whether we have a PXC200A */
+       if (btv->cardid == PX_PXC200A_CARDID)  {
+          bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
+          bitmask |= 7<<4; /* the DAC */
+       }
+       btwrite(bitmask, BT848_GPIO_OUT_EN);
+
+       bitmask = btread(BT848_GPIO_DATA);
+       if (btv->cardid == PX_PXC200A_CARDID)
+         bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
+       else /* older device */
+         bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
+       btwrite(bitmask,BT848_GPIO_DATA);
+
+       /*
+        * Was "to be safe, set the bt848 to input 0"
+        * Actually, since it's ok at load time, better not messing
+        * with these bits (on PXC200AF you need to set mux 2 here)
+        *
+        * needed because bttv-driver sets mux before calling this function
+        */
+       if (btv->cardid == PX_PXC200A_CARDID)
+         btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
+       else /* older device */
+         btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
+
+       printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux);
+}
+
+/* ----------------------------------------------------------------------- */
+/* motherboard chipset specific stuff                                      */
+
+void __devinit bttv_check_chipset(void)
+{
+       int pcipci_fail = 0;
+       struct pci_dev *dev = NULL;
+
+       if (pci_pci_problems & PCIPCI_FAIL)
+               pcipci_fail = 1;
+       if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
+               triton1 = 1;
+       if (pci_pci_problems & PCIPCI_VSFX)
+               vsfx = 1;
+#ifdef PCIPCI_ALIMAGIK
+       if (pci_pci_problems & PCIPCI_ALIMAGIK)
+               latency = 0x0A;
+#endif
+
+
+       /* print warnings about any quirks found */
+       if (triton1)
+               printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
+       if (vsfx)
+               printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
+       if (pcipci_fail) {
+               printk(KERN_INFO "bttv: bttv and your chipset may not work "
+                                                       "together.\n");
+               if (!no_overlay) {
+                       printk(KERN_INFO "bttv: overlay will be disabled.\n");
+                       no_overlay = 1;
+               } else {
+                       printk(KERN_INFO "bttv: overlay forced. Use this "
+                                               "option at your own risk.\n");
+               }
+       }
+       if (UNSET != latency)
+               printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
+       while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                     PCI_DEVICE_ID_INTEL_82441, dev))) {
+               unsigned char b;
+               pci_read_config_byte(dev, 0x53, &b);
+               if (bttv_debug)
+                       printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
+                              "bufcon=0x%02x\n",b);
+       }
+}
+
+int __devinit bttv_handle_chipset(struct bttv *btv)
+{
+       unsigned char command;
+
+       if (!triton1 && !vsfx && UNSET == latency)
+               return 0;
+
+       if (bttv_verbose) {
+               if (triton1)
+                       printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr);
+               if (vsfx && btv->id >= 878)
+                       printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr);
+               if (UNSET != latency)
+                       printk(KERN_INFO "bttv%d: setting pci timer to %d\n",
+                              btv->c.nr,latency);
+       }
+
+       if (btv->id < 878) {
+               /* bt848 (mis)uses a bit in the irq mask for etbf */
+               if (triton1)
+                       btv->triton1 = BT848_INT_ETBF;
+       } else {
+               /* bt878 has a bit in the pci config space for it */
+               pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
+               if (triton1)
+                       command |= BT878_EN_TBFX;
+               if (vsfx)
+                       command |= BT878_EN_VSFX;
+               pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
+       }
+       if (UNSET != latency)
+               pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
+       return 0;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
new file mode 100644 (file)
index 0000000..74def9c
--- /dev/null
@@ -0,0 +1,4321 @@
+/*
+
+    bttv - Bt848 frame grabber driver
+
+    Copyright (C) 1996,97,98 Ralph  Metzler <rjkm@thp.uni-koeln.de>
+                          & Marcus Metzler <mocm@thp.uni-koeln.de>
+    (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
+
+    some v4l2 code lines are taken from Justin's bttv2 driver which is
+    (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the 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/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <media/tvaudio.h>
+#include <media/msp3400.h>
+
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <media/rds.h>
+
+
+unsigned int bttv_num;                 /* number of Bt848s in use */
+struct bttv bttvs[BTTV_MAX];
+
+unsigned int bttv_debug;
+unsigned int bttv_verbose = 1;
+unsigned int bttv_gpio;
+
+/* config variables */
+#ifdef __BIG_ENDIAN
+static unsigned int bigendian=1;
+#else
+static unsigned int bigendian;
+#endif
+static unsigned int radio[BTTV_MAX];
+static unsigned int irq_debug;
+static unsigned int gbuffers = 8;
+static unsigned int gbufsize = 0x208000;
+
+static int video_nr = -1;
+static int radio_nr = -1;
+static int vbi_nr = -1;
+static int debug_latency;
+
+static unsigned int fdsr;
+
+/* options */
+static unsigned int combfilter;
+static unsigned int lumafilter;
+static unsigned int automute    = 1;
+static unsigned int chroma_agc;
+static unsigned int adc_crush   = 1;
+static unsigned int whitecrush_upper = 0xCF;
+static unsigned int whitecrush_lower = 0x7F;
+static unsigned int vcr_hack;
+static unsigned int irq_iswitch;
+static unsigned int uv_ratio    = 50;
+static unsigned int full_luma_range;
+static unsigned int coring;
+extern int no_overlay;
+
+/* API features (turn on/off stuff for testing) */
+static unsigned int v4l2        = 1;
+
+/* insmod args */
+module_param(bttv_verbose,      int, 0644);
+module_param(bttv_gpio,         int, 0644);
+module_param(bttv_debug,        int, 0644);
+module_param(irq_debug,         int, 0644);
+module_param(debug_latency,     int, 0644);
+
+module_param(fdsr,              int, 0444);
+module_param(video_nr,          int, 0444);
+module_param(radio_nr,          int, 0444);
+module_param(vbi_nr,            int, 0444);
+module_param(gbuffers,          int, 0444);
+module_param(gbufsize,          int, 0444);
+
+module_param(v4l2,              int, 0644);
+module_param(bigendian,         int, 0644);
+module_param(irq_iswitch,       int, 0644);
+module_param(combfilter,        int, 0444);
+module_param(lumafilter,        int, 0444);
+module_param(automute,          int, 0444);
+module_param(chroma_agc,        int, 0444);
+module_param(adc_crush,         int, 0444);
+module_param(whitecrush_upper,  int, 0444);
+module_param(whitecrush_lower,  int, 0444);
+module_param(vcr_hack,          int, 0444);
+module_param(uv_ratio,          int, 0444);
+module_param(full_luma_range,   int, 0444);
+module_param(coring,            int, 0444);
+
+module_param_array(radio, int, NULL, 0444);
+
+MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
+MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
+MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
+MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
+MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
+MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
+MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
+MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
+MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
+MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
+MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
+MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
+MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
+MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
+MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
+
+MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
+MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
+MODULE_LICENSE("GPL");
+
+/* ----------------------------------------------------------------------- */
+/* sysfs                                                                   */
+
+static ssize_t show_card(struct class_device *cd, char *buf)
+{
+       struct video_device *vfd = to_video_device(cd);
+       struct bttv *btv = dev_get_drvdata(vfd->dev);
+       return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
+}
+static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+
+/* ----------------------------------------------------------------------- */
+/* static data                                                             */
+
+/* special timing tables from conexant... */
+static u8 SRAM_Table[][60] =
+{
+       /* PAL digital input over GPIO[7:0] */
+       {
+               45, // 45 bytes following
+               0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
+               0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
+               0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
+               0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
+               0x37,0x00,0xAF,0x21,0x00
+       },
+       /* NTSC digital input over GPIO[7:0] */
+       {
+               51, // 51 bytes following
+               0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
+               0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
+               0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
+               0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
+               0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
+               0x00,
+       },
+       // TGB_NTSC392 // quartzsight
+       // This table has been modified to be used for Fusion Rev D
+       {
+               0x2A, // size of table = 42
+               0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
+               0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
+               0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
+               0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
+               0x20, 0x00
+       }
+};
+
+const struct bttv_tvnorm bttv_tvnorms[] = {
+       /* PAL-BDGHI */
+       /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+       /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
+       {
+               .v4l2_id        = V4L2_STD_PAL,
+               .name           = "PAL",
+               .Fsc            = 35468950,
+               .swidth         = 924,
+               .sheight        = 576,
+               .totalwidth     = 1135,
+               .adelay         = 0x7f,
+               .bdelay         = 0x72,
+               .iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+               .scaledtwidth   = 1135,
+               .hdelayx1       = 186,
+               .hactivex1      = 924,
+               .vdelay         = 0x20,
+               .vbipack        = 255,
+               .sram           = 0,
+               /* ITU-R frame line number of the first VBI line
+                  we can capture, of the first and second field. */
+               .vbistart       = { 7,320 },
+       },{
+               .v4l2_id        = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
+               .name           = "NTSC",
+               .Fsc            = 28636363,
+               .swidth         = 768,
+               .sheight        = 480,
+               .totalwidth     = 910,
+               .adelay         = 0x68,
+               .bdelay         = 0x5d,
+               .iform          = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+               .scaledtwidth   = 910,
+               .hdelayx1       = 128,
+               .hactivex1      = 910,
+               .vdelay         = 0x1a,
+               .vbipack        = 144,
+               .sram           = 1,
+               .vbistart       = { 10, 273 },
+       },{
+               .v4l2_id        = V4L2_STD_SECAM,
+               .name           = "SECAM",
+               .Fsc            = 35468950,
+               .swidth         = 924,
+               .sheight        = 576,
+               .totalwidth     = 1135,
+               .adelay         = 0x7f,
+               .bdelay         = 0xb0,
+               .iform          = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+               .scaledtwidth   = 1135,
+               .hdelayx1       = 186,
+               .hactivex1      = 922,
+               .vdelay         = 0x20,
+               .vbipack        = 255,
+               .sram           = 0, /* like PAL, correct? */
+               .vbistart       = { 7, 320 },
+       },{
+               .v4l2_id        = V4L2_STD_PAL_Nc,
+               .name           = "PAL-Nc",
+               .Fsc            = 28636363,
+               .swidth         = 640,
+               .sheight        = 576,
+               .totalwidth     = 910,
+               .adelay         = 0x68,
+               .bdelay         = 0x5d,
+               .iform          = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+               .scaledtwidth   = 780,
+               .hdelayx1       = 130,
+               .hactivex1      = 734,
+               .vdelay         = 0x1a,
+               .vbipack        = 144,
+               .sram           = -1,
+               .vbistart       = { 7, 320 },
+       },{
+               .v4l2_id        = V4L2_STD_PAL_M,
+               .name           = "PAL-M",
+               .Fsc            = 28636363,
+               .swidth         = 640,
+               .sheight        = 480,
+               .totalwidth     = 910,
+               .adelay         = 0x68,
+               .bdelay         = 0x5d,
+               .iform          = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+               .scaledtwidth   = 780,
+               .hdelayx1       = 135,
+               .hactivex1      = 754,
+               .vdelay         = 0x1a,
+               .vbipack        = 144,
+               .sram           = -1,
+               .vbistart       = { 10, 273 },
+       },{
+               .v4l2_id        = V4L2_STD_PAL_N,
+               .name           = "PAL-N",
+               .Fsc            = 35468950,
+               .swidth         = 768,
+               .sheight        = 576,
+               .totalwidth     = 1135,
+               .adelay         = 0x7f,
+               .bdelay         = 0x72,
+               .iform          = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+               .scaledtwidth   = 944,
+               .hdelayx1       = 186,
+               .hactivex1      = 922,
+               .vdelay         = 0x20,
+               .vbipack        = 144,
+               .sram           = -1,
+               .vbistart       = { 7, 320},
+       },{
+               .v4l2_id        = V4L2_STD_NTSC_M_JP,
+               .name           = "NTSC-JP",
+               .Fsc            = 28636363,
+               .swidth         = 640,
+               .sheight        = 480,
+               .totalwidth     = 910,
+               .adelay         = 0x68,
+               .bdelay         = 0x5d,
+               .iform          = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+               .scaledtwidth   = 780,
+               .hdelayx1       = 135,
+               .hactivex1      = 754,
+               .vdelay         = 0x16,
+               .vbipack        = 144,
+               .sram           = -1,
+               .vbistart       = {10, 273},
+       },{
+               /* that one hopefully works with the strange timing
+                * which video recorders produce when playing a NTSC
+                * tape on a PAL TV ... */
+               .v4l2_id        = V4L2_STD_PAL_60,
+               .name           = "PAL-60",
+               .Fsc            = 35468950,
+               .swidth         = 924,
+               .sheight        = 480,
+               .totalwidth     = 1135,
+               .adelay         = 0x7f,
+               .bdelay         = 0x72,
+               .iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+               .scaledtwidth   = 1135,
+               .hdelayx1       = 186,
+               .hactivex1      = 924,
+               .vdelay         = 0x1a,
+               .vbipack        = 255,
+               .vtotal         = 524,
+               .sram           = -1,
+               .vbistart       = { 10, 273 },
+       }
+};
+static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
+
+/* ----------------------------------------------------------------------- */
+/* bttv format list
+   packed pixel formats must come first */
+static const struct bttv_format bttv_formats[] = {
+       {
+               .name     = "8 bpp, gray",
+               .palette  = VIDEO_PALETTE_GREY,
+               .fourcc   = V4L2_PIX_FMT_GREY,
+               .btformat = BT848_COLOR_FMT_Y8,
+               .depth    = 8,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "8 bpp, dithered color",
+               .palette  = VIDEO_PALETTE_HI240,
+               .fourcc   = V4L2_PIX_FMT_HI240,
+               .btformat = BT848_COLOR_FMT_RGB8,
+               .depth    = 8,
+               .flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
+       },{
+               .name     = "15 bpp RGB, le",
+               .palette  = VIDEO_PALETTE_RGB555,
+               .fourcc   = V4L2_PIX_FMT_RGB555,
+               .btformat = BT848_COLOR_FMT_RGB15,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "15 bpp RGB, be",
+               .palette  = -1,
+               .fourcc   = V4L2_PIX_FMT_RGB555X,
+               .btformat = BT848_COLOR_FMT_RGB15,
+               .btswap   = 0x03, /* byteswap */
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "16 bpp RGB, le",
+               .palette  = VIDEO_PALETTE_RGB565,
+               .fourcc   = V4L2_PIX_FMT_RGB565,
+               .btformat = BT848_COLOR_FMT_RGB16,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "16 bpp RGB, be",
+               .palette  = -1,
+               .fourcc   = V4L2_PIX_FMT_RGB565X,
+               .btformat = BT848_COLOR_FMT_RGB16,
+               .btswap   = 0x03, /* byteswap */
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "24 bpp RGB, le",
+               .palette  = VIDEO_PALETTE_RGB24,
+               .fourcc   = V4L2_PIX_FMT_BGR24,
+               .btformat = BT848_COLOR_FMT_RGB24,
+               .depth    = 24,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "32 bpp RGB, le",
+               .palette  = VIDEO_PALETTE_RGB32,
+               .fourcc   = V4L2_PIX_FMT_BGR32,
+               .btformat = BT848_COLOR_FMT_RGB32,
+               .depth    = 32,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "32 bpp RGB, be",
+               .palette  = -1,
+               .fourcc   = V4L2_PIX_FMT_RGB32,
+               .btformat = BT848_COLOR_FMT_RGB32,
+               .btswap   = 0x0f, /* byte+word swap */
+               .depth    = 32,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "4:2:2, packed, YUYV",
+               .palette  = VIDEO_PALETTE_YUV422,
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .btformat = BT848_COLOR_FMT_YUY2,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "4:2:2, packed, YUYV",
+               .palette  = VIDEO_PALETTE_YUYV,
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .btformat = BT848_COLOR_FMT_YUY2,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "4:2:2, packed, UYVY",
+               .palette  = VIDEO_PALETTE_UYVY,
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .btformat = BT848_COLOR_FMT_YUY2,
+               .btswap   = 0x03, /* byteswap */
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PACKED,
+       },{
+               .name     = "4:2:2, planar, Y-Cb-Cr",
+               .palette  = VIDEO_PALETTE_YUV422P,
+               .fourcc   = V4L2_PIX_FMT_YUV422P,
+               .btformat = BT848_COLOR_FMT_YCrCb422,
+               .depth    = 16,
+               .flags    = FORMAT_FLAGS_PLANAR,
+               .hshift   = 1,
+               .vshift   = 0,
+       },{
+               .name     = "4:2:0, planar, Y-Cb-Cr",
+               .palette  = VIDEO_PALETTE_YUV420P,
+               .fourcc   = V4L2_PIX_FMT_YUV420,
+               .btformat = BT848_COLOR_FMT_YCrCb422,
+               .depth    = 12,
+               .flags    = FORMAT_FLAGS_PLANAR,
+               .hshift   = 1,
+               .vshift   = 1,
+       },{
+               .name     = "4:2:0, planar, Y-Cr-Cb",
+               .palette  = -1,
+               .fourcc   = V4L2_PIX_FMT_YVU420,
+               .btformat = BT848_COLOR_FMT_YCrCb422,
+               .depth    = 12,
+               .flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
+               .hshift   = 1,
+               .vshift   = 1,
+       },{
+               .name     = "4:1:1, planar, Y-Cb-Cr",
+               .palette  = VIDEO_PALETTE_YUV411P,
+               .fourcc   = V4L2_PIX_FMT_YUV411P,
+               .btformat = BT848_COLOR_FMT_YCrCb411,
+               .depth    = 12,
+               .flags    = FORMAT_FLAGS_PLANAR,
+               .hshift   = 2,
+               .vshift   = 0,
+       },{
+               .name     = "4:1:0, planar, Y-Cb-Cr",
+               .palette  = VIDEO_PALETTE_YUV410P,
+               .fourcc   = V4L2_PIX_FMT_YUV410,
+               .btformat = BT848_COLOR_FMT_YCrCb411,
+               .depth    = 9,
+               .flags    = FORMAT_FLAGS_PLANAR,
+               .hshift   = 2,
+               .vshift   = 2,
+       },{
+               .name     = "4:1:0, planar, Y-Cr-Cb",
+               .palette  = -1,
+               .fourcc   = V4L2_PIX_FMT_YVU410,
+               .btformat = BT848_COLOR_FMT_YCrCb411,
+               .depth    = 9,
+               .flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
+               .hshift   = 2,
+               .vshift   = 2,
+       },{
+               .name     = "raw scanlines",
+               .palette  = VIDEO_PALETTE_RAW,
+               .fourcc   = -1,
+               .btformat = BT848_COLOR_FMT_RAW,
+               .depth    = 8,
+               .flags    = FORMAT_FLAGS_RAW,
+       }
+};
+static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
+
+/* ----------------------------------------------------------------------- */
+
+#define V4L2_CID_PRIVATE_CHROMA_AGC  (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_COMBFILTER  (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_LUMAFILTER  (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AGC_CRUSH   (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_VCR_HACK    (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER   (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER   (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_UV_RATIO    (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE    (V4L2_CID_PRIVATE_BASE + 9)
+#define V4L2_CID_PRIVATE_CORING      (V4L2_CID_PRIVATE_BASE + 10)
+#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 11)
+
+static const struct v4l2_queryctrl no_ctl = {
+       .name  = "42",
+       .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+static const struct v4l2_queryctrl bttv_ctls[] = {
+       /* --- video --- */
+       {
+               .id            = V4L2_CID_BRIGHTNESS,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 256,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_CONTRAST,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 128,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_SATURATION,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 128,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_HUE,
+               .name          = "Hue",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 256,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },
+       /* --- audio --- */
+       {
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .name          = "Volume",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 65535,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_BALANCE,
+               .name          = "Balance",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_BASS,
+               .name          = "Bass",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_AUDIO_TREBLE,
+               .name          = "Treble",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 32768,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },
+       /* --- private --- */
+       {
+               .id            = V4L2_CID_PRIVATE_CHROMA_AGC,
+               .name          = "chroma agc",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_COMBFILTER,
+               .name          = "combfilter",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_AUTOMUTE,
+               .name          = "automute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_LUMAFILTER,
+               .name          = "luma decimation filter",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_AGC_CRUSH,
+               .name          = "agc crush",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_VCR_HACK,
+               .name          = "vcr hack",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
+               .name          = "whitecrush upper",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 0xCF,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
+               .name          = "whitecrush lower",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 0x7F,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_PRIVATE_UV_RATIO,
+               .name          = "uv ratio",
+               .minimum       = 0,
+               .maximum       = 100,
+               .step          = 1,
+               .default_value = 50,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
+               .name          = "full luma range",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       },{
+               .id            = V4L2_CID_PRIVATE_CORING,
+               .name          = "coring",
+               .minimum       = 0,
+               .maximum       = 3,
+               .step          = 1,
+               .default_value = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       }
+
+
+
+};
+static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
+
+/* ----------------------------------------------------------------------- */
+/* resource management                                                     */
+
+static
+int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
+{
+       if (fh->resources & bit)
+               /* have it already allocated */
+               return 1;
+
+       /* is it free? */
+       mutex_lock(&btv->reslock);
+       if (btv->resources & bit) {
+               /* no, someone else uses it */
+               mutex_unlock(&btv->reslock);
+               return 0;
+       }
+       /* it's free, grab it */
+       fh->resources  |= bit;
+       btv->resources |= bit;
+       mutex_unlock(&btv->reslock);
+       return 1;
+}
+
+static
+int check_btres(struct bttv_fh *fh, int bit)
+{
+       return (fh->resources & bit);
+}
+
+static
+int locked_btres(struct bttv *btv, int bit)
+{
+       return (btv->resources & bit);
+}
+
+static
+void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
+{
+       if ((fh->resources & bits) != bits) {
+               /* trying to free ressources not allocated by us ... */
+               printk("bttv: BUG! (btres)\n");
+       }
+       mutex_lock(&btv->reslock);
+       fh->resources  &= ~bits;
+       btv->resources &= ~bits;
+       mutex_unlock(&btv->reslock);
+}
+
+/* ----------------------------------------------------------------------- */
+/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC          */
+
+/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
+   PLL_X = Reference pre-divider (0=1, 1=2)
+   PLL_C = Post divider (0=6, 1=4)
+   PLL_I = Integer input
+   PLL_F = Fractional input
+
+   F_input = 28.636363 MHz:
+   PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
+*/
+
+static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
+{
+       unsigned char fl, fh, fi;
+
+       /* prevent overflows */
+       fin/=4;
+       fout/=4;
+
+       fout*=12;
+       fi=fout/fin;
+
+       fout=(fout%fin)*256;
+       fh=fout/fin;
+
+       fout=(fout%fin)*256;
+       fl=fout/fin;
+
+       btwrite(fl, BT848_PLL_F_LO);
+       btwrite(fh, BT848_PLL_F_HI);
+       btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
+}
+
+static void set_pll(struct bttv *btv)
+{
+       int i;
+
+       if (!btv->pll.pll_crystal)
+               return;
+
+       if (btv->pll.pll_ofreq == btv->pll.pll_current) {
+               dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
+               return;
+       }
+
+       if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
+               /* no PLL needed */
+               if (btv->pll.pll_current == 0)
+                       return;
+               bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
+                       btv->c.nr,btv->pll.pll_ifreq);
+               btwrite(0x00,BT848_TGCTRL);
+               btwrite(0x00,BT848_PLL_XCI);
+               btv->pll.pll_current = 0;
+               return;
+       }
+
+       bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
+               btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+       set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+
+       for (i=0; i<10; i++) {
+               /*  Let other people run while the PLL stabilizes */
+               bttv_printk(".");
+               msleep(10);
+
+               if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
+                       btwrite(0,BT848_DSTATUS);
+               } else {
+                       btwrite(0x08,BT848_TGCTRL);
+                       btv->pll.pll_current = btv->pll.pll_ofreq;
+                       bttv_printk(" ok\n");
+                       return;
+               }
+       }
+       btv->pll.pll_current = -1;
+       bttv_printk("failed\n");
+       return;
+}
+
+/* used to switch between the bt848's analog/digital video capture modes */
+static void bt848A_set_timing(struct bttv *btv)
+{
+       int i, len;
+       int table_idx = bttv_tvnorms[btv->tvnorm].sram;
+       int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;
+
+       if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
+               dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
+                       btv->c.nr,table_idx);
+
+               /* timing change...reset timing generator address */
+               btwrite(0x00, BT848_TGCTRL);
+               btwrite(0x02, BT848_TGCTRL);
+               btwrite(0x00, BT848_TGCTRL);
+
+               len=SRAM_Table[table_idx][0];
+               for(i = 1; i <= len; i++)
+                       btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
+               btv->pll.pll_ofreq = 27000000;
+
+               set_pll(btv);
+               btwrite(0x11, BT848_TGCTRL);
+               btwrite(0x41, BT848_DVSIF);
+       } else {
+               btv->pll.pll_ofreq = fsc;
+               set_pll(btv);
+               btwrite(0x0, BT848_DVSIF);
+       }
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void bt848_bright(struct bttv *btv, int bright)
+{
+       int value;
+
+       // printk("bttv: set bright: %d\n",bright); // DEBUG
+       btv->bright = bright;
+
+       /* We want -128 to 127 we get 0-65535 */
+       value = (bright >> 8) - 128;
+       btwrite(value & 0xff, BT848_BRIGHT);
+}
+
+static void bt848_hue(struct bttv *btv, int hue)
+{
+       int value;
+
+       btv->hue = hue;
+
+       /* -128 to 127 */
+       value = (hue >> 8) - 128;
+       btwrite(value & 0xff, BT848_HUE);
+}
+
+static void bt848_contrast(struct bttv *btv, int cont)
+{
+       int value,hibit;
+
+       btv->contrast = cont;
+
+       /* 0-511 */
+       value = (cont  >> 7);
+       hibit = (value >> 6) & 4;
+       btwrite(value & 0xff, BT848_CONTRAST_LO);
+       btaor(hibit, ~4, BT848_E_CONTROL);
+       btaor(hibit, ~4, BT848_O_CONTROL);
+}
+
+static void bt848_sat(struct bttv *btv, int color)
+{
+       int val_u,val_v,hibits;
+
+       btv->saturation = color;
+
+       /* 0-511 for the color */
+       val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
+       val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
+       hibits  = (val_u >> 7) & 2;
+       hibits |= (val_v >> 8) & 1;
+       btwrite(val_u & 0xff, BT848_SAT_U_LO);
+       btwrite(val_v & 0xff, BT848_SAT_V_LO);
+       btaor(hibits, ~3, BT848_E_CONTROL);
+       btaor(hibits, ~3, BT848_O_CONTROL);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int
+video_mux(struct bttv *btv, unsigned int input)
+{
+       int mux,mask2;
+
+       if (input >= bttv_tvcards[btv->c.type].video_inputs)
+               return -EINVAL;
+
+       /* needed by RemoteVideo MX */
+       mask2 = bttv_tvcards[btv->c.type].gpiomask2;
+       if (mask2)
+               gpio_inout(mask2,mask2);
+
+       if (input == btv->svhs)  {
+               btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
+               btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
+       } else {
+               btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+               btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+       }
+       mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
+       btaor(mux<<5, ~(3<<5), BT848_IFORM);
+       dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
+               btv->c.nr,input,mux);
+
+       /* card specific hook */
+       if(bttv_tvcards[btv->c.type].muxsel_hook)
+               bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
+       return 0;
+}
+
+static char *audio_modes[] = {
+       "audio: tuner", "audio: radio", "audio: extern",
+       "audio: intern", "audio: mute"
+};
+
+static int
+audio_mux(struct bttv *btv, int input, int mute)
+{
+       int gpio_val, signal;
+       struct v4l2_control ctrl;
+       struct i2c_client *c;
+
+       gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
+                  bttv_tvcards[btv->c.type].gpiomask);
+       signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
+
+       btv->mute = mute;
+       btv->audio = input;
+
+       /* automute */
+       mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
+
+       if (mute)
+               gpio_val = bttv_tvcards[btv->c.type].gpiomute;
+       else
+               gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
+
+       gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
+       if (in_interrupt())
+               return 0;
+
+       ctrl.id = V4L2_CID_AUDIO_MUTE;
+       ctrl.value = btv->mute;
+       bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
+       c = btv->i2c_msp34xx_client;
+       if (c) {
+               struct v4l2_routing route;
+
+               /* Note: the inputs tuner/radio/extern/intern are translated
+                  to msp routings. This assumes common behavior for all msp3400
+                  based TV cards. When this assumption fails, then the
+                  specific MSP routing must be added to the card table.
+                  For now this is sufficient. */
+               switch (input) {
+               case TVAUDIO_INPUT_RADIO:
+                       route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
+                                   MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+                       break;
+               case TVAUDIO_INPUT_EXTERN:
+                       route.input = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1,
+                                   MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+                       break;
+               case TVAUDIO_INPUT_INTERN:
+                       /* Yes, this is the same input as for RADIO. I doubt
+                          if this is ever used. The only board with an INTERN
+                          input is the BTTV_BOARD_AVERMEDIA98. I wonder how
+                          that was tested. My guess is that the whole INTERN
+                          input does not work. */
+                       route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
+                                   MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+                       break;
+               case TVAUDIO_INPUT_TUNER:
+               default:
+                       route.input = MSP_INPUT_DEFAULT;
+                       break;
+               }
+               route.output = MSP_OUTPUT_DEFAULT;
+               c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       }
+       c = btv->i2c_tvaudio_client;
+       if (c) {
+               struct v4l2_routing route;
+
+               route.input = input;
+               route.output = 0;
+               c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       }
+       return 0;
+}
+
+static inline int
+audio_mute(struct bttv *btv, int mute)
+{
+       return audio_mux(btv, btv->audio, mute);
+}
+
+static inline int
+audio_input(struct bttv *btv, int input)
+{
+       return audio_mux(btv, input, btv->mute);
+}
+
+static void
+i2c_vidiocschan(struct bttv *btv)
+{
+       struct video_channel c;
+
+       memset(&c,0,sizeof(c));
+       c.norm    = btv->tvnorm;
+       c.channel = btv->input;
+       bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
+       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+               bttv_tda9880_setnorm(btv,c.norm);
+}
+
+static int
+set_tvnorm(struct bttv *btv, unsigned int norm)
+{
+       const struct bttv_tvnorm *tvnorm;
+
+       if (norm < 0 || norm >= BTTV_TVNORMS)
+               return -EINVAL;
+
+       btv->tvnorm = norm;
+       tvnorm = &bttv_tvnorms[norm];
+
+       btwrite(tvnorm->adelay, BT848_ADELAY);
+       btwrite(tvnorm->bdelay, BT848_BDELAY);
+       btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
+             BT848_IFORM);
+       btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
+       btwrite(1, BT848_VBI_PACK_DEL);
+       bt848A_set_timing(btv);
+
+       switch (btv->c.type) {
+       case BTTV_BOARD_VOODOOTV_FM:
+               bttv_tda9880_setnorm(btv,norm);
+               break;
+       }
+       return 0;
+}
+
+static void
+set_input(struct bttv *btv, unsigned int input)
+{
+       unsigned long flags;
+
+       btv->input = input;
+       if (irq_iswitch) {
+               spin_lock_irqsave(&btv->s_lock,flags);
+               if (btv->curr.frame_irq) {
+                       /* active capture -> delayed input switch */
+                       btv->new_input = input;
+               } else {
+                       video_mux(btv,input);
+               }
+               spin_unlock_irqrestore(&btv->s_lock,flags);
+       } else {
+               video_mux(btv,input);
+       }
+       audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
+                      TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
+       set_tvnorm(btv,btv->tvnorm);
+       i2c_vidiocschan(btv);
+}
+
+static void init_irqreg(struct bttv *btv)
+{
+       /* clear status */
+       btwrite(0xfffffUL, BT848_INT_STAT);
+
+       if (bttv_tvcards[btv->c.type].no_video) {
+               /* i2c only */
+               btwrite(BT848_INT_I2CDONE,
+                       BT848_INT_MASK);
+       } else {
+               /* full video */
+               btwrite((btv->triton1)  |
+                       (btv->gpioirq ? BT848_INT_GPINT : 0) |
+                       BT848_INT_SCERR |
+                       (fdsr ? BT848_INT_FDSR : 0) |
+                       BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
+                       BT848_INT_FMTCHG|BT848_INT_HLOCK|
+                       BT848_INT_I2CDONE,
+                       BT848_INT_MASK);
+       }
+}
+
+static void init_bt848(struct bttv *btv)
+{
+       int val;
+
+       if (bttv_tvcards[btv->c.type].no_video) {
+               /* very basic init only */
+               init_irqreg(btv);
+               return;
+       }
+
+       btwrite(0x00, BT848_CAP_CTL);
+       btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
+       btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
+
+       /* set planar and packed mode trigger points and         */
+       /* set rising edge of inverted GPINTR pin as irq trigger */
+       btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+               BT848_GPIO_DMA_CTL_PLTP1_16|
+               BT848_GPIO_DMA_CTL_PLTP23_16|
+               BT848_GPIO_DMA_CTL_GPINTC|
+               BT848_GPIO_DMA_CTL_GPINTI,
+               BT848_GPIO_DMA_CTL);
+
+       val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
+       btwrite(val, BT848_E_SCLOOP);
+       btwrite(val, BT848_O_SCLOOP);
+
+       btwrite(0x20, BT848_E_VSCALE_HI);
+       btwrite(0x20, BT848_O_VSCALE_HI);
+       btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+               BT848_ADC);
+
+       btwrite(whitecrush_upper, BT848_WC_UP);
+       btwrite(whitecrush_lower, BT848_WC_DOWN);
+
+       if (btv->opt_lumafilter) {
+               btwrite(0, BT848_E_CONTROL);
+               btwrite(0, BT848_O_CONTROL);
+       } else {
+               btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+               btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+       }
+
+       bt848_bright(btv,   btv->bright);
+       bt848_hue(btv,      btv->hue);
+       bt848_contrast(btv, btv->contrast);
+       bt848_sat(btv,      btv->saturation);
+
+       /* interrupt */
+       init_irqreg(btv);
+}
+
+static void bttv_reinit_bt848(struct bttv *btv)
+{
+       unsigned long flags;
+
+       if (bttv_verbose)
+               printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
+       spin_lock_irqsave(&btv->s_lock,flags);
+       btv->errors=0;
+       bttv_set_dma(btv,0);
+       spin_unlock_irqrestore(&btv->s_lock,flags);
+
+       init_bt848(btv);
+       btv->pll.pll_current = -1;
+       set_input(btv,btv->input);
+}
+
+static int get_control(struct bttv *btv, struct v4l2_control *c)
+{
+       struct video_audio va;
+       int i;
+
+       for (i = 0; i < BTTV_CTLS; i++)
+               if (bttv_ctls[i].id == c->id)
+                       break;
+       if (i == BTTV_CTLS)
+               return -EINVAL;
+       if (i >= 4 && i <= 8) {
+               memset(&va,0,sizeof(va));
+               bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
+               if (btv->audio_hook)
+                       btv->audio_hook(btv,&va,0);
+       }
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               c->value = btv->bright;
+               break;
+       case V4L2_CID_HUE:
+               c->value = btv->hue;
+               break;
+       case V4L2_CID_CONTRAST:
+               c->value = btv->contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               c->value = btv->saturation;
+               break;
+
+       case V4L2_CID_AUDIO_MUTE:
+               c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+               c->value = va.volume;
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               c->value = va.balance;
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               c->value = va.bass;
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               c->value = va.treble;
+               break;
+
+       case V4L2_CID_PRIVATE_CHROMA_AGC:
+               c->value = btv->opt_chroma_agc;
+               break;
+       case V4L2_CID_PRIVATE_COMBFILTER:
+               c->value = btv->opt_combfilter;
+               break;
+       case V4L2_CID_PRIVATE_LUMAFILTER:
+               c->value = btv->opt_lumafilter;
+               break;
+       case V4L2_CID_PRIVATE_AUTOMUTE:
+               c->value = btv->opt_automute;
+               break;
+       case V4L2_CID_PRIVATE_AGC_CRUSH:
+               c->value = btv->opt_adc_crush;
+               break;
+       case V4L2_CID_PRIVATE_VCR_HACK:
+               c->value = btv->opt_vcr_hack;
+               break;
+       case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
+               c->value = btv->opt_whitecrush_upper;
+               break;
+       case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
+               c->value = btv->opt_whitecrush_lower;
+               break;
+       case V4L2_CID_PRIVATE_UV_RATIO:
+               c->value = btv->opt_uv_ratio;
+               break;
+       case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+               c->value = btv->opt_full_luma_range;
+               break;
+       case V4L2_CID_PRIVATE_CORING:
+               c->value = btv->opt_coring;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int set_control(struct bttv *btv, struct v4l2_control *c)
+{
+       struct video_audio va;
+       int i,val;
+
+       for (i = 0; i < BTTV_CTLS; i++)
+               if (bttv_ctls[i].id == c->id)
+                       break;
+       if (i == BTTV_CTLS)
+               return -EINVAL;
+       if (i >= 4 && i <= 8) {
+               memset(&va,0,sizeof(va));
+               bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
+               if (btv->audio_hook)
+                       btv->audio_hook(btv,&va,0);
+       }
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               bt848_bright(btv,c->value);
+               break;
+       case V4L2_CID_HUE:
+               bt848_hue(btv,c->value);
+               break;
+       case V4L2_CID_CONTRAST:
+               bt848_contrast(btv,c->value);
+               break;
+       case V4L2_CID_SATURATION:
+               bt848_sat(btv,c->value);
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               if (c->value) {
+                       va.flags |= VIDEO_AUDIO_MUTE;
+                       audio_mute(btv, 1);
+               } else {
+                       va.flags &= ~VIDEO_AUDIO_MUTE;
+                       audio_mute(btv, 0);
+               }
+               break;
+
+       case V4L2_CID_AUDIO_VOLUME:
+               va.volume = c->value;
+               break;
+       case V4L2_CID_AUDIO_BALANCE:
+               va.balance = c->value;
+               break;
+       case V4L2_CID_AUDIO_BASS:
+               va.bass = c->value;
+               break;
+       case V4L2_CID_AUDIO_TREBLE:
+               va.treble = c->value;
+               break;
+
+       case V4L2_CID_PRIVATE_CHROMA_AGC:
+               btv->opt_chroma_agc = c->value;
+               val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
+               btwrite(val, BT848_E_SCLOOP);
+               btwrite(val, BT848_O_SCLOOP);
+               break;
+       case V4L2_CID_PRIVATE_COMBFILTER:
+               btv->opt_combfilter = c->value;
+               break;
+       case V4L2_CID_PRIVATE_LUMAFILTER:
+               btv->opt_lumafilter = c->value;
+               if (btv->opt_lumafilter) {
+                       btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
+                       btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
+               } else {
+                       btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+                       btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+               }
+               break;
+       case V4L2_CID_PRIVATE_AUTOMUTE:
+               btv->opt_automute = c->value;
+               break;
+       case V4L2_CID_PRIVATE_AGC_CRUSH:
+               btv->opt_adc_crush = c->value;
+               btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+                       BT848_ADC);
+               break;
+       case V4L2_CID_PRIVATE_VCR_HACK:
+               btv->opt_vcr_hack = c->value;
+               break;
+       case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
+               btv->opt_whitecrush_upper = c->value;
+               btwrite(c->value, BT848_WC_UP);
+               break;
+       case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
+               btv->opt_whitecrush_lower = c->value;
+               btwrite(c->value, BT848_WC_DOWN);
+               break;
+       case V4L2_CID_PRIVATE_UV_RATIO:
+               btv->opt_uv_ratio = c->value;
+               bt848_sat(btv, btv->saturation);
+               break;
+       case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+               btv->opt_full_luma_range = c->value;
+               btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
+               break;
+       case V4L2_CID_PRIVATE_CORING:
+               btv->opt_coring = c->value;
+               btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (i >= 4 && i <= 8) {
+               bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
+               if (btv->audio_hook)
+                       btv->audio_hook(btv,&va,1);
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void bttv_gpio_tracking(struct bttv *btv, char *comment)
+{
+       unsigned int outbits, data;
+       outbits = btread(BT848_GPIO_OUT_EN);
+       data    = btread(BT848_GPIO_DATA);
+       printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
+              btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
+}
+
+static void bttv_field_count(struct bttv *btv)
+{
+       int need_count = 0;
+
+       if (btv->users)
+               need_count++;
+
+       if (need_count) {
+               /* start field counter */
+               btor(BT848_INT_VSYNC,BT848_INT_MASK);
+       } else {
+               /* stop field counter */
+               btand(~BT848_INT_VSYNC,BT848_INT_MASK);
+               btv->field_count = 0;
+       }
+}
+
+static const struct bttv_format*
+format_by_palette(int palette)
+{
+       unsigned int i;
+
+       for (i = 0; i < BTTV_FORMATS; i++) {
+               if (-1 == bttv_formats[i].palette)
+                       continue;
+               if (bttv_formats[i].palette == palette)
+                       return bttv_formats+i;
+       }
+       return NULL;
+}
+
+static const struct bttv_format*
+format_by_fourcc(int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < BTTV_FORMATS; i++) {
+               if (-1 == bttv_formats[i].fourcc)
+                       continue;
+               if (bttv_formats[i].fourcc == fourcc)
+                       return bttv_formats+i;
+       }
+       return NULL;
+}
+
+/* ----------------------------------------------------------------------- */
+/* misc helpers                                                            */
+
+static int
+bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
+                   struct bttv_buffer *new)
+{
+       struct bttv_buffer *old;
+       unsigned long flags;
+       int retval = 0;
+
+       dprintk("switch_overlay: enter [new=%p]\n",new);
+       if (new)
+               new->vb.state = STATE_DONE;
+       spin_lock_irqsave(&btv->s_lock,flags);
+       old = btv->screen;
+       btv->screen = new;
+       btv->loop_irq |= 1;
+       bttv_set_dma(btv, 0x03);
+       spin_unlock_irqrestore(&btv->s_lock,flags);
+       if (NULL == new)
+               free_btres(btv,fh,RESOURCE_OVERLAY);
+       if (NULL != old) {
+               dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
+               bttv_dma_free(&fh->cap,btv, old);
+               kfree(old);
+       }
+       dprintk("switch_overlay: done\n");
+       return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+/* video4linux (1) interface                                               */
+
+static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
+                              struct bttv_buffer *buf,
+                              const struct bttv_format *fmt,
+                              unsigned int width, unsigned int height,
+                              enum v4l2_field field)
+{
+       int redo_dma_risc = 0;
+       int rc;
+
+       /* check settings */
+       if (NULL == fmt)
+               return -EINVAL;
+       if (fmt->btformat == BT848_COLOR_FMT_RAW) {
+               width  = RAW_BPL;
+               height = RAW_LINES*2;
+               if (width*height > buf->vb.bsize)
+                       return -EINVAL;
+               buf->vb.size = buf->vb.bsize;
+       } else {
+               if (width  < 48 ||
+                   height < 32 ||
+                   width  > bttv_tvnorms[btv->tvnorm].swidth ||
+                   height > bttv_tvnorms[btv->tvnorm].sheight)
+                       return -EINVAL;
+               buf->vb.size = (width * height * fmt->depth) >> 3;
+               if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+                       return -EINVAL;
+       }
+
+       /* alloc + fill struct bttv_buffer (if changed) */
+       if (buf->vb.width != width || buf->vb.height != height ||
+           buf->vb.field != field ||
+           buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
+               buf->vb.width  = width;
+               buf->vb.height = height;
+               buf->vb.field  = field;
+               buf->tvnorm    = btv->tvnorm;
+               buf->fmt       = fmt;
+               redo_dma_risc = 1;
+       }
+
+       /* alloc risc memory */
+       if (STATE_NEEDS_INIT == buf->vb.state) {
+               redo_dma_risc = 1;
+               if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
+                       goto fail;
+       }
+
+       if (redo_dma_risc)
+               if (0 != (rc = bttv_buffer_risc(btv,buf)))
+                       goto fail;
+
+       buf->vb.state = STATE_PREPARED;
+       return 0;
+
+ fail:
+       bttv_dma_free(q,btv,buf);
+       return rc;
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+       struct bttv_fh *fh = q->priv_data;
+
+       *size = fh->fmt->depth*fh->width*fh->height >> 3;
+       if (0 == *count)
+               *count = gbuffers;
+       while (*size * *count > gbuffers * gbufsize)
+               (*count)--;
+       return 0;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+              enum v4l2_field field)
+{
+       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+       struct bttv_fh *fh = q->priv_data;
+
+       return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
+                                  fh->width, fh->height, field);
+}
+
+static void
+buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+       struct bttv_fh *fh = q->priv_data;
+       struct bttv    *btv = fh->btv;
+
+       buf->vb.state = STATE_QUEUED;
+       list_add_tail(&buf->vb.queue,&btv->capture);
+       if (!btv->curr.frame_irq) {
+               btv->loop_irq |= 1;
+               bttv_set_dma(btv, 0x03);
+       }
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+       struct bttv_fh *fh = q->priv_data;
+
+       bttv_dma_free(&fh->cap,fh->btv,buf);
+}
+
+static struct videobuf_queue_ops bttv_video_qops = {
+       .buf_setup    = buffer_setup,
+       .buf_prepare  = buffer_prepare,
+       .buf_queue    = buffer_queue,
+       .buf_release  = buffer_release,
+};
+
+static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
+{
+       switch (cmd) {
+       case BTTV_VERSION:
+               return BTTV_VERSION_CODE;
+
+       /* ***  v4l1  *** ************************************************ */
+       case VIDIOCGFREQ:
+       {
+               unsigned long *freq = arg;
+               *freq = btv->freq;
+               return 0;
+       }
+       case VIDIOCSFREQ:
+       {
+               unsigned long *freq = arg;
+               mutex_lock(&btv->lock);
+               btv->freq=*freq;
+               bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
+               if (btv->has_matchbox && btv->radio_user)
+                       tea5757_set_freq(btv,*freq);
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+
+       case VIDIOCGTUNER:
+       {
+               struct video_tuner *v = arg;
+
+               if (UNSET == bttv_tvcards[btv->c.type].tuner)
+                       return -EINVAL;
+               if (v->tuner) /* Only tuner 0 */
+                       return -EINVAL;
+               strcpy(v->name, "Television");
+               v->rangelow  = 0;
+               v->rangehigh = 0x7FFFFFFF;
+               v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
+               v->mode      = btv->tvnorm;
+               v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
+               bttv_call_i2c_clients(btv,cmd,v);
+               return 0;
+       }
+       case VIDIOCSTUNER:
+       {
+               struct video_tuner *v = arg;
+
+               if (v->tuner) /* Only tuner 0 */
+                       return -EINVAL;
+               if (v->mode >= BTTV_TVNORMS)
+                       return -EINVAL;
+
+               mutex_lock(&btv->lock);
+               set_tvnorm(btv,v->mode);
+               bttv_call_i2c_clients(btv,cmd,v);
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *v = arg;
+               unsigned int channel = v->channel;
+
+               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+                       return -EINVAL;
+               v->tuners=0;
+               v->flags = VIDEO_VC_AUDIO;
+               v->type = VIDEO_TYPE_CAMERA;
+               v->norm = btv->tvnorm;
+               if (channel == bttv_tvcards[btv->c.type].tuner)  {
+                       strcpy(v->name,"Television");
+                       v->flags|=VIDEO_VC_TUNER;
+                       v->type=VIDEO_TYPE_TV;
+                       v->tuners=1;
+               } else if (channel == btv->svhs) {
+                       strcpy(v->name,"S-Video");
+               } else {
+                       sprintf(v->name,"Composite%d",channel);
+               }
+               return 0;
+       }
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *v = arg;
+               unsigned int channel = v->channel;
+
+               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+                       return -EINVAL;
+               if (v->norm >= BTTV_TVNORMS)
+                       return -EINVAL;
+
+               mutex_lock(&btv->lock);
+               if (channel == btv->input &&
+                   v->norm == btv->tvnorm) {
+                       /* nothing to do */
+                       mutex_unlock(&btv->lock);
+                       return 0;
+               }
+
+               btv->tvnorm = v->norm;
+               set_input(btv,v->channel);
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+
+       case VIDIOCGAUDIO:
+       {
+               struct video_audio *v = arg;
+
+               memset(v,0,sizeof(*v));
+               strcpy(v->name,"Television");
+               v->flags |= VIDEO_AUDIO_MUTABLE;
+               v->mode  = VIDEO_SOUND_MONO;
+
+               mutex_lock(&btv->lock);
+               bttv_call_i2c_clients(btv,cmd,v);
+
+               /* card specific hooks */
+               if (btv->audio_hook)
+                       btv->audio_hook(btv,v,0);
+
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+       case VIDIOCSAUDIO:
+       {
+               struct video_audio *v = arg;
+               unsigned int audio = v->audio;
+
+               if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
+                       return -EINVAL;
+
+               mutex_lock(&btv->lock);
+               audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
+               bttv_call_i2c_clients(btv,cmd,v);
+
+               /* card specific hooks */
+               if (btv->audio_hook)
+                       btv->audio_hook(btv,v,1);
+
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+
+       /* ***  v4l2  *** ************************************************ */
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *e = arg;
+               unsigned int index = e->index;
+
+               if (index >= BTTV_TVNORMS)
+                       return -EINVAL;
+               v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
+                                        bttv_tvnorms[e->index].name);
+               e->index = index;
+               return 0;
+       }
+       case VIDIOC_G_STD:
+       {
+               v4l2_std_id *id = arg;
+               *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
+               return 0;
+       }
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *id = arg;
+               unsigned int i;
+
+               for (i = 0; i < BTTV_TVNORMS; i++)
+                       if (*id & bttv_tvnorms[i].v4l2_id)
+                               break;
+               if (i == BTTV_TVNORMS)
+                       return -EINVAL;
+
+               mutex_lock(&btv->lock);
+               set_tvnorm(btv,i);
+               i2c_vidiocschan(btv);
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+       case VIDIOC_QUERYSTD:
+       {
+               v4l2_std_id *id = arg;
+
+               if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
+                       *id = V4L2_STD_625_50;
+               else
+                       *id = V4L2_STD_525_60;
+               return 0;
+       }
+
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *i = arg;
+               unsigned int n;
+
+               n = i->index;
+               if (n >= bttv_tvcards[btv->c.type].video_inputs)
+                       return -EINVAL;
+               memset(i,0,sizeof(*i));
+               i->index    = n;
+               i->type     = V4L2_INPUT_TYPE_CAMERA;
+               i->audioset = 0;
+               if (i->index == bttv_tvcards[btv->c.type].tuner) {
+                       sprintf(i->name, "Television");
+                       i->type  = V4L2_INPUT_TYPE_TUNER;
+                       i->tuner = 0;
+               } else if (i->index == btv->svhs) {
+                       sprintf(i->name, "S-Video");
+               } else {
+                       sprintf(i->name,"Composite%d",i->index);
+               }
+               if (i->index == btv->input) {
+                       __u32 dstatus = btread(BT848_DSTATUS);
+                       if (0 == (dstatus & BT848_DSTATUS_PRES))
+                               i->status |= V4L2_IN_ST_NO_SIGNAL;
+                       if (0 == (dstatus & BT848_DSTATUS_HLOC))
+                               i->status |= V4L2_IN_ST_NO_H_LOCK;
+               }
+               for (n = 0; n < BTTV_TVNORMS; n++)
+                       i->std |= bttv_tvnorms[n].v4l2_id;
+               return 0;
+       }
+       case VIDIOC_G_INPUT:
+       {
+               int *i = arg;
+               *i = btv->input;
+               return 0;
+       }
+       case VIDIOC_S_INPUT:
+       {
+               unsigned int *i = arg;
+
+               if (*i > bttv_tvcards[btv->c.type].video_inputs)
+                       return -EINVAL;
+               mutex_lock(&btv->lock);
+               set_input(btv,*i);
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+
+       case VIDIOC_G_TUNER:
+       {
+               struct v4l2_tuner *t = arg;
+
+               if (UNSET == bttv_tvcards[btv->c.type].tuner)
+                       return -EINVAL;
+               if (0 != t->index)
+                       return -EINVAL;
+               mutex_lock(&btv->lock);
+               memset(t,0,sizeof(*t));
+               strcpy(t->name, "Television");
+               t->type       = V4L2_TUNER_ANALOG_TV;
+               t->capability = V4L2_TUNER_CAP_NORM;
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+               if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
+                       t->signal = 0xffff;
+               {
+                       struct video_tuner tuner;
+
+                       memset(&tuner, 0, sizeof (tuner));
+                       tuner.rangehigh = 0xffffffffUL;
+                       bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
+                       t->rangelow = tuner.rangelow;
+                       t->rangehigh = tuner.rangehigh;
+               }
+               {
+                       /* Hmmm ... */
+                       struct video_audio va;
+                       memset(&va, 0, sizeof(struct video_audio));
+                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
+                       if (btv->audio_hook)
+                               btv->audio_hook(btv,&va,0);
+                       if(va.mode & VIDEO_SOUND_STEREO) {
+                               t->audmode     = V4L2_TUNER_MODE_STEREO;
+                               t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+                       }
+                       if(va.mode & VIDEO_SOUND_LANG1) {
+                               t->audmode    = V4L2_TUNER_MODE_LANG1;
+                               t->rxsubchans = V4L2_TUNER_SUB_LANG1
+                                       | V4L2_TUNER_SUB_LANG2;
+                       }
+               }
+               /* FIXME: fill capability+audmode */
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *t = arg;
+
+               if (UNSET == bttv_tvcards[btv->c.type].tuner)
+                       return -EINVAL;
+               if (0 != t->index)
+                       return -EINVAL;
+               mutex_lock(&btv->lock);
+               {
+                       struct video_audio va;
+                       memset(&va, 0, sizeof(struct video_audio));
+                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
+                       if (t->audmode == V4L2_TUNER_MODE_MONO)
+                               va.mode = VIDEO_SOUND_MONO;
+                       else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
+                                t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
+                               va.mode = VIDEO_SOUND_STEREO;
+                       else if (t->audmode == V4L2_TUNER_MODE_LANG1)
+                               va.mode = VIDEO_SOUND_LANG1;
+                       else if (t->audmode == V4L2_TUNER_MODE_LANG2)
+                               va.mode = VIDEO_SOUND_LANG2;
+                       bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
+                       if (btv->audio_hook)
+                               btv->audio_hook(btv,&va,1);
+               }
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+
+       case VIDIOC_G_FREQUENCY:
+       {
+               struct v4l2_frequency *f = arg;
+
+               memset(f,0,sizeof(*f));
+               f->type = V4L2_TUNER_ANALOG_TV;
+               f->frequency = btv->freq;
+               return 0;
+       }
+       case VIDIOC_S_FREQUENCY:
+       {
+               struct v4l2_frequency *f = arg;
+
+               if (unlikely(f->tuner != 0))
+                       return -EINVAL;
+               if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
+                       return -EINVAL;
+               mutex_lock(&btv->lock);
+               btv->freq = f->frequency;
+               bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
+               if (btv->has_matchbox && btv->radio_user)
+                       tea5757_set_freq(btv,btv->freq);
+               mutex_unlock(&btv->lock);
+               return 0;
+       }
+       case VIDIOC_LOG_STATUS:
+       {
+               bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+               return 0;
+       }
+
+       default:
+               return -ENOIOCTLCMD;
+
+       }
+       return 0;
+}
+
+static int verify_window(const struct bttv_tvnorm *tvn,
+                        struct v4l2_window *win, int fixup)
+{
+       enum v4l2_field field;
+       int maxw, maxh;
+
+       if (win->w.width  < 48 || win->w.height < 32)
+               return -EINVAL;
+       if (win->clipcount > 2048)
+               return -EINVAL;
+
+       field = win->field;
+       maxw  = tvn->swidth;
+       maxh  = tvn->sheight;
+
+       if (V4L2_FIELD_ANY == field) {
+               field = (win->w.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
+       }
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!fixup && (win->w.width > maxw || win->w.height > maxh))
+               return -EINVAL;
+
+       if (win->w.width > maxw)
+               win->w.width = maxw;
+       if (win->w.height > maxh)
+               win->w.height = maxh;
+       win->field = field;
+       return 0;
+}
+
+static int setup_window(struct bttv_fh *fh, struct bttv *btv,
+                       struct v4l2_window *win, int fixup)
+{
+       struct v4l2_clip *clips = NULL;
+       int n,size,retval = 0;
+
+       if (NULL == fh->ovfmt)
+               return -EINVAL;
+       if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
+               return -EINVAL;
+       retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
+       if (0 != retval)
+               return retval;
+
+       /* copy clips  --  luckily v4l1 + v4l2 are binary
+          compatible here ...*/
+       n = win->clipcount;
+       size = sizeof(*clips)*(n+4);
+       clips = kmalloc(size,GFP_KERNEL);
+       if (NULL == clips)
+               return -ENOMEM;
+       if (n > 0) {
+               if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
+                       kfree(clips);
+                       return -EFAULT;
+               }
+       }
+       /* clip against screen */
+       if (NULL != btv->fbuf.base)
+               n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
+                                     &win->w, clips, n);
+       btcx_sort_clips(clips,n);
+
+       /* 4-byte alignments */
+       switch (fh->ovfmt->depth) {
+       case 8:
+       case 24:
+               btcx_align(&win->w, clips, n, 3);
+               break;
+       case 16:
+               btcx_align(&win->w, clips, n, 1);
+               break;
+       case 32:
+               /* no alignment fixups needed */
+               break;
+       default:
+               BUG();
+       }
+
+       mutex_lock(&fh->cap.lock);
+               kfree(fh->ov.clips);
+       fh->ov.clips    = clips;
+       fh->ov.nclips   = n;
+
+       fh->ov.w        = win->w;
+       fh->ov.field    = win->field;
+       fh->ov.setup_ok = 1;
+       btv->init.ov.w.width   = win->w.width;
+       btv->init.ov.w.height  = win->w.height;
+       btv->init.ov.field     = win->field;
+
+       /* update overlay if needed */
+       retval = 0;
+       if (check_btres(fh, RESOURCE_OVERLAY)) {
+               struct bttv_buffer *new;
+
+               new = videobuf_alloc(sizeof(*new));
+               bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+               retval = bttv_switch_overlay(btv,fh,new);
+       }
+       mutex_unlock(&fh->cap.lock);
+       return retval;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
+{
+       struct videobuf_queue* q = NULL;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               q = &fh->cap;
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               q = &fh->vbi;
+               break;
+       default:
+               BUG();
+       }
+       return q;
+}
+
+static int bttv_resource(struct bttv_fh *fh)
+{
+       int res = 0;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               res = RESOURCE_VIDEO;
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               res = RESOURCE_VBI;
+               break;
+       default:
+               BUG();
+       }
+       return res;
+}
+
+static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
+{
+       struct videobuf_queue *q = bttv_queue(fh);
+       int res = bttv_resource(fh);
+
+       if (check_btres(fh,res))
+               return -EBUSY;
+       if (videobuf_queue_is_busy(q))
+               return -EBUSY;
+       fh->type = type;
+       return 0;
+}
+
+static void
+pix_format_set_size     (struct v4l2_pix_format *       f,
+                        const struct bttv_format *     fmt,
+                        unsigned int                   width,
+                        unsigned int                   height)
+{
+       f->width = width;
+       f->height = height;
+
+       if (fmt->flags & FORMAT_FLAGS_PLANAR) {
+               f->bytesperline = width; /* Y plane */
+               f->sizeimage = (width * height * fmt->depth) >> 3;
+       } else {
+               f->bytesperline = (width * fmt->depth) >> 3;
+               f->sizeimage = height * f->bytesperline;
+       }
+}
+
+static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+{
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
+               pix_format_set_size (&f->fmt.pix, fh->fmt,
+                                    fh->width, fh->height);
+               f->fmt.pix.field        = fh->cap.field;
+               f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+               return 0;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               memset(&f->fmt.win,0,sizeof(struct v4l2_window));
+               f->fmt.win.w     = fh->ov.w;
+               f->fmt.win.field = fh->ov.field;
+               return 0;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               bttv_vbi_get_fmt(fh,f);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
+                       struct v4l2_format *f)
+{
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       {
+               const struct bttv_format *fmt;
+               enum v4l2_field field;
+               unsigned int maxw,maxh;
+
+               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+               if (NULL == fmt)
+                       return -EINVAL;
+
+               /* fixup format */
+               maxw  = bttv_tvnorms[btv->tvnorm].swidth;
+               maxh  = bttv_tvnorms[btv->tvnorm].sheight;
+               field = f->fmt.pix.field;
+               if (V4L2_FIELD_ANY == field)
+                       field = (f->fmt.pix.height > maxh/2)
+                               ? V4L2_FIELD_INTERLACED
+                               : V4L2_FIELD_BOTTOM;
+               if (V4L2_FIELD_SEQ_BT == field)
+                       field = V4L2_FIELD_SEQ_TB;
+               switch (field) {
+               case V4L2_FIELD_TOP:
+               case V4L2_FIELD_BOTTOM:
+               case V4L2_FIELD_ALTERNATE:
+                       maxh = maxh/2;
+                       break;
+               case V4L2_FIELD_INTERLACED:
+                       break;
+               case V4L2_FIELD_SEQ_TB:
+                       if (fmt->flags & FORMAT_FLAGS_PLANAR)
+                               return -EINVAL;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               /* update data for the application */
+               f->fmt.pix.field = field;
+               if (f->fmt.pix.width  < 48)
+                       f->fmt.pix.width  = 48;
+               if (f->fmt.pix.height < 32)
+                       f->fmt.pix.height = 32;
+               if (f->fmt.pix.width  > maxw)
+                       f->fmt.pix.width = maxw;
+               if (f->fmt.pix.height > maxh)
+                       f->fmt.pix.height = maxh;
+               pix_format_set_size (&f->fmt.pix, fmt,
+                                    f->fmt.pix.width & ~3,
+                                    f->fmt.pix.height);
+
+               return 0;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return verify_window(&bttv_tvnorms[btv->tvnorm],
+                                    &f->fmt.win, 1);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               bttv_vbi_try_fmt(fh,f);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
+                     struct v4l2_format *f)
+{
+       int retval;
+
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       {
+               const struct bttv_format *fmt;
+
+               retval = bttv_switch_type(fh,f->type);
+               if (0 != retval)
+                       return retval;
+               retval = bttv_try_fmt(fh,btv,f);
+               if (0 != retval)
+                       return retval;
+               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+               /* update our state informations */
+               mutex_lock(&fh->cap.lock);
+               fh->fmt              = fmt;
+               fh->cap.field        = f->fmt.pix.field;
+               fh->cap.last         = V4L2_FIELD_NONE;
+               fh->width            = f->fmt.pix.width;
+               fh->height           = f->fmt.pix.height;
+               btv->init.fmt        = fmt;
+               btv->init.width      = f->fmt.pix.width;
+               btv->init.height     = f->fmt.pix.height;
+               mutex_unlock(&fh->cap.lock);
+
+               return 0;
+       }
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
+               return setup_window(fh, btv, &f->fmt.win, 1);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               retval = bttv_switch_type(fh,f->type);
+               if (0 != retval)
+                       return retval;
+               if (locked_btres(fh->btv, RESOURCE_VBI))
+                       return -EBUSY;
+               bttv_vbi_try_fmt(fh,f);
+               bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
+               bttv_vbi_get_fmt(fh,f);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bttv_do_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, void *arg)
+{
+       struct bttv_fh *fh  = file->private_data;
+       struct bttv    *btv = fh->btv;
+       unsigned long flags;
+       int retval = 0;
+
+       if (bttv_debug > 1)
+               v4l_print_ioctl(btv->c.name, cmd);
+
+       if (btv->errors)
+               bttv_reinit_bt848(btv);
+
+       switch (cmd) {
+       case VIDIOCSFREQ:
+       case VIDIOCSTUNER:
+       case VIDIOCSCHAN:
+       case VIDIOC_S_CTRL:
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_S_FREQUENCY:
+               retval = v4l2_prio_check(&btv->prio,&fh->prio);
+               if (0 != retval)
+                       return retval;
+       };
+
+       switch (cmd) {
+
+       /* ***  v4l1  *** ************************************************ */
+       case VIDIOCGCAP:
+       {
+               struct video_capability *cap = arg;
+
+               memset(cap,0,sizeof(*cap));
+               strcpy(cap->name,btv->video_dev->name);
+               if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+                       /* vbi */
+                       cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
+               } else {
+                       /* others */
+                       cap->type = VID_TYPE_CAPTURE|
+                               VID_TYPE_TUNER|
+                               VID_TYPE_CLIPPING|
+                               VID_TYPE_SCALES;
+                       if (no_overlay <= 0)
+                               cap->type |= VID_TYPE_OVERLAY;
+
+                       cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
+                       cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
+                       cap->minwidth  = 48;
+                       cap->minheight = 32;
+               }
+               cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
+               cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
+               return 0;
+       }
+
+       case VIDIOCGPICT:
+       {
+               struct video_picture *pic = arg;
+
+               memset(pic,0,sizeof(*pic));
+               pic->brightness = btv->bright;
+               pic->contrast   = btv->contrast;
+               pic->hue        = btv->hue;
+               pic->colour     = btv->saturation;
+               if (fh->fmt) {
+                       pic->depth   = fh->fmt->depth;
+                       pic->palette = fh->fmt->palette;
+               }
+               return 0;
+       }
+       case VIDIOCSPICT:
+       {
+               struct video_picture *pic = arg;
+               const struct bttv_format *fmt;
+
+               fmt = format_by_palette(pic->palette);
+               if (NULL == fmt)
+                       return -EINVAL;
+               mutex_lock(&fh->cap.lock);
+               if (fmt->depth != pic->depth) {
+                       retval = -EINVAL;
+                       goto fh_unlock_and_return;
+               }
+               if (fmt->flags & FORMAT_FLAGS_RAW) {
+                       /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
+                          RAW_LINES * 2. F1 is stored at offset 0, F2
+                          at buffer size / 2. */
+                       fh->width = RAW_BPL;
+                       fh->height = gbufsize / RAW_BPL;
+                       btv->init.width  = RAW_BPL;
+                       btv->init.height = gbufsize / RAW_BPL;
+               }
+               fh->ovfmt   = fmt;
+               fh->fmt     = fmt;
+               btv->init.ovfmt   = fmt;
+               btv->init.fmt     = fmt;
+               if (bigendian) {
+                       /* dirty hack time:  swap bytes for overlay if the
+                          display adaptor is big endian (insmod option) */
+                       if (fmt->palette == VIDEO_PALETTE_RGB555 ||
+                           fmt->palette == VIDEO_PALETTE_RGB565 ||
+                           fmt->palette == VIDEO_PALETTE_RGB32) {
+                               fh->ovfmt = fmt+1;
+                       }
+               }
+               bt848_bright(btv,pic->brightness);
+               bt848_contrast(btv,pic->contrast);
+               bt848_hue(btv,pic->hue);
+               bt848_sat(btv,pic->colour);
+               mutex_unlock(&fh->cap.lock);
+               return 0;
+       }
+
+       case VIDIOCGWIN:
+       {
+               struct video_window *win = arg;
+
+               memset(win,0,sizeof(*win));
+               win->x      = fh->ov.w.left;
+               win->y      = fh->ov.w.top;
+               win->width  = fh->ov.w.width;
+               win->height = fh->ov.w.height;
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window *win = arg;
+               struct v4l2_window w2;
+
+               if (no_overlay > 0) {
+                       printk ("VIDIOCSWIN: no_overlay\n");
+                       return -EINVAL;
+               }
+
+               w2.field = V4L2_FIELD_ANY;
+               w2.w.left    = win->x;
+               w2.w.top     = win->y;
+               w2.w.width   = win->width;
+               w2.w.height  = win->height;
+               w2.clipcount = win->clipcount;
+               w2.clips     = (struct v4l2_clip __user *)win->clips;
+               retval = setup_window(fh, btv, &w2, 0);
+               if (0 == retval) {
+                       /* on v4l1 this ioctl affects the read() size too */
+                       fh->width  = fh->ov.w.width;
+                       fh->height = fh->ov.w.height;
+                       btv->init.width  = fh->ov.w.width;
+                       btv->init.height = fh->ov.w.height;
+               }
+               return retval;
+       }
+
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer *fbuf = arg;
+
+               fbuf->base          = btv->fbuf.base;
+               fbuf->width         = btv->fbuf.fmt.width;
+               fbuf->height        = btv->fbuf.fmt.height;
+               fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
+               if (fh->ovfmt)
+                       fbuf->depth = fh->ovfmt->depth;
+               return 0;
+       }
+       case VIDIOCSFBUF:
+       {
+               struct video_buffer *fbuf = arg;
+               const struct bttv_format *fmt;
+               unsigned long end;
+
+               if(!capable(CAP_SYS_ADMIN) &&
+                  !capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+               end = (unsigned long)fbuf->base +
+                       fbuf->height * fbuf->bytesperline;
+               mutex_lock(&fh->cap.lock);
+               retval = -EINVAL;
+
+               switch (fbuf->depth) {
+               case 8:
+                       fmt = format_by_palette(VIDEO_PALETTE_HI240);
+                       break;
+               case 16:
+                       fmt = format_by_palette(VIDEO_PALETTE_RGB565);
+                       break;
+               case 24:
+                       fmt = format_by_palette(VIDEO_PALETTE_RGB24);
+                       break;
+               case 32:
+                       fmt = format_by_palette(VIDEO_PALETTE_RGB32);
+                       break;
+               case 15:
+                       fbuf->depth = 16;
+                       fmt = format_by_palette(VIDEO_PALETTE_RGB555);
+                       break;
+               default:
+                       fmt = NULL;
+                       break;
+               }
+               if (NULL == fmt)
+                       goto fh_unlock_and_return;
+
+               fh->ovfmt = fmt;
+               fh->fmt   = fmt;
+               btv->init.ovfmt = fmt;
+               btv->init.fmt   = fmt;
+               btv->fbuf.base             = fbuf->base;
+               btv->fbuf.fmt.width        = fbuf->width;
+               btv->fbuf.fmt.height       = fbuf->height;
+               if (fbuf->bytesperline)
+                       btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
+               else
+                       btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
+               mutex_unlock(&fh->cap.lock);
+               return 0;
+       }
+
+       case VIDIOCCAPTURE:
+       case VIDIOC_OVERLAY:
+       {
+               struct bttv_buffer *new;
+               int *on = arg;
+
+               if (*on) {
+                       /* verify args */
+                       if (NULL == btv->fbuf.base)
+                               return -EINVAL;
+                       if (!fh->ov.setup_ok) {
+                               dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
+                               return -EINVAL;
+                       }
+               }
+
+               if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
+                       return -EBUSY;
+
+               mutex_lock(&fh->cap.lock);
+               if (*on) {
+                       fh->ov.tvnorm = btv->tvnorm;
+                       new = videobuf_alloc(sizeof(*new));
+                       bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+               } else {
+                       new = NULL;
+               }
+
+               /* switch over */
+               retval = bttv_switch_overlay(btv,fh,new);
+               mutex_unlock(&fh->cap.lock);
+               return retval;
+       }
+
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *mbuf = arg;
+               unsigned int i;
+
+               mutex_lock(&fh->cap.lock);
+               retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
+                                            V4L2_MEMORY_MMAP);
+               if (retval < 0)
+                       goto fh_unlock_and_return;
+               memset(mbuf,0,sizeof(*mbuf));
+               mbuf->frames = gbuffers;
+               mbuf->size   = gbuffers * gbufsize;
+               for (i = 0; i < gbuffers; i++)
+                       mbuf->offsets[i] = i * gbufsize;
+               mutex_unlock(&fh->cap.lock);
+               return 0;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *vm = arg;
+               struct bttv_buffer *buf;
+               enum v4l2_field field;
+
+               if (vm->frame >= VIDEO_MAX_FRAME)
+                       return -EINVAL;
+
+               mutex_lock(&fh->cap.lock);
+               retval = -EINVAL;
+               buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
+               if (NULL == buf)
+                       goto fh_unlock_and_return;
+               if (0 == buf->vb.baddr)
+                       goto fh_unlock_and_return;
+               if (buf->vb.state == STATE_QUEUED ||
+                   buf->vb.state == STATE_ACTIVE)
+                       goto fh_unlock_and_return;
+
+               field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_BOTTOM;
+               retval = bttv_prepare_buffer(&fh->cap,btv,buf,
+                                            format_by_palette(vm->format),
+                                            vm->width,vm->height,field);
+               if (0 != retval)
+                       goto fh_unlock_and_return;
+               spin_lock_irqsave(&btv->s_lock,flags);
+               buffer_queue(&fh->cap,&buf->vb);
+               spin_unlock_irqrestore(&btv->s_lock,flags);
+               mutex_unlock(&fh->cap.lock);
+               return 0;
+       }
+       case VIDIOCSYNC:
+       {
+               int *frame = arg;
+               struct bttv_buffer *buf;
+
+               if (*frame >= VIDEO_MAX_FRAME)
+                       return -EINVAL;
+
+               mutex_lock(&fh->cap.lock);
+               retval = -EINVAL;
+               buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
+               if (NULL == buf)
+                       goto fh_unlock_and_return;
+               retval = videobuf_waiton(&buf->vb,0,1);
+               if (0 != retval)
+                       goto fh_unlock_and_return;
+               switch (buf->vb.state) {
+               case STATE_ERROR:
+                       retval = -EIO;
+                       /* fall through */
+               case STATE_DONE:
+                       videobuf_dma_sync(&fh->cap,&buf->vb.dma);
+                       bttv_dma_free(&fh->cap,btv,buf);
+                       break;
+               default:
+                       retval = -EINVAL;
+                       break;
+               }
+               mutex_unlock(&fh->cap.lock);
+               return retval;
+       }
+
+       case VIDIOCGVBIFMT:
+       {
+               struct vbi_format *fmt = (void *) arg;
+               struct v4l2_format fmt2;
+
+               if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
+                       retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
+                       if (0 != retval)
+                               return retval;
+               }
+               bttv_vbi_get_fmt(fh, &fmt2);
+
+               memset(fmt,0,sizeof(*fmt));
+               fmt->sampling_rate    = fmt2.fmt.vbi.sampling_rate;
+               fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
+               fmt->sample_format    = VIDEO_PALETTE_RAW;
+               fmt->start[0]         = fmt2.fmt.vbi.start[0];
+               fmt->count[0]         = fmt2.fmt.vbi.count[0];
+               fmt->start[1]         = fmt2.fmt.vbi.start[1];
+               fmt->count[1]         = fmt2.fmt.vbi.count[1];
+               if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
+                       fmt->flags   |= VBI_UNSYNC;
+               if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
+                       fmt->flags   |= VBI_INTERLACED;
+               return 0;
+       }
+       case VIDIOCSVBIFMT:
+       {
+               struct vbi_format *fmt = (void *) arg;
+               struct v4l2_format fmt2;
+
+               retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
+               if (0 != retval)
+                       return retval;
+               bttv_vbi_get_fmt(fh, &fmt2);
+
+               if (fmt->sampling_rate    != fmt2.fmt.vbi.sampling_rate     ||
+                   fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line  ||
+                   fmt->sample_format    != VIDEO_PALETTE_RAW              ||
+                   fmt->start[0]         != fmt2.fmt.vbi.start[0]          ||
+                   fmt->start[1]         != fmt2.fmt.vbi.start[1]          ||
+                   fmt->count[0]         != fmt->count[1]                  ||
+                   fmt->count[0]         <  1                              ||
+                   fmt->count[0]         >  32 /* VBI_MAXLINES */)
+                       return -EINVAL;
+
+               bttv_vbi_setlines(fh,btv,fmt->count[0]);
+               return 0;
+       }
+
+       case BTTV_VERSION:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGCHAN:
+       case VIDIOCSCHAN:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return bttv_common_ioctls(btv,cmd,arg);
+
+       /* ***  v4l2  *** ************************************************ */
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = arg;
+
+               if (0 == v4l2)
+                       return -EINVAL;
+               memset(cap, 0, sizeof (*cap));
+               strlcpy(cap->driver, "bttv", sizeof (cap->driver));
+               strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
+               snprintf(cap->bus_info, sizeof (cap->bus_info),
+                        "PCI:%s", pci_name(btv->c.pci));
+               cap->version = BTTV_VERSION_CODE;
+               cap->capabilities =
+                       V4L2_CAP_VIDEO_CAPTURE |
+                       V4L2_CAP_VBI_CAPTURE |
+                       V4L2_CAP_READWRITE |
+                       V4L2_CAP_STREAMING;
+               if (no_overlay <= 0)
+                       cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+               if (bttv_tvcards[btv->c.type].tuner != UNSET &&
+                   bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
+                       cap->capabilities |= V4L2_CAP_TUNER;
+               return 0;
+       }
+
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *f = arg;
+               enum v4l2_buf_type type;
+               unsigned int i;
+               int index;
+
+               type  = f->type;
+               if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
+                       /* vbi */
+                       index = f->index;
+                       if (0 != index)
+                               return -EINVAL;
+                       memset(f,0,sizeof(*f));
+                       f->index       = index;
+                       f->type        = type;
+                       f->pixelformat = V4L2_PIX_FMT_GREY;
+                       strcpy(f->description,"vbi data");
+                       return 0;
+               }
+
+               /* video capture + overlay */
+               index = -1;
+               for (i = 0; i < BTTV_FORMATS; i++) {
+                       if (bttv_formats[i].fourcc != -1)
+                               index++;
+                       if ((unsigned int)index == f->index)
+                               break;
+               }
+               if (BTTV_FORMATS == i)
+                       return -EINVAL;
+
+               switch (f->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
+                               return -EINVAL;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               memset(f,0,sizeof(*f));
+               f->index       = index;
+               f->type        = type;
+               f->pixelformat = bttv_formats[i].fourcc;
+               strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
+               return 0;
+       }
+
+       case VIDIOC_TRY_FMT:
+       {
+               struct v4l2_format *f = arg;
+               return bttv_try_fmt(fh,btv,f);
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = arg;
+               return bttv_g_fmt(fh,f);
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+               return bttv_s_fmt(fh,btv,f);
+       }
+
+       case VIDIOC_G_FBUF:
+       {
+               struct v4l2_framebuffer *fb = arg;
+
+               *fb = btv->fbuf;
+               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+               if (fh->ovfmt)
+                       fb->fmt.pixelformat  = fh->ovfmt->fourcc;
+               return 0;
+       }
+       case VIDIOC_S_FBUF:
+       {
+               struct v4l2_framebuffer *fb = arg;
+               const struct bttv_format *fmt;
+
+               if(!capable(CAP_SYS_ADMIN) &&
+                  !capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+
+               /* check args */
+               fmt = format_by_fourcc(fb->fmt.pixelformat);
+               if (NULL == fmt)
+                       return -EINVAL;
+               if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
+                       return -EINVAL;
+
+               mutex_lock(&fh->cap.lock);
+               retval = -EINVAL;
+               if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+                       if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
+                               goto fh_unlock_and_return;
+                       if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
+                               goto fh_unlock_and_return;
+               }
+
+               /* ok, accept it */
+               btv->fbuf.base       = fb->base;
+               btv->fbuf.fmt.width  = fb->fmt.width;
+               btv->fbuf.fmt.height = fb->fmt.height;
+               if (0 != fb->fmt.bytesperline)
+                       btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
+               else
+                       btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
+
+               retval = 0;
+               fh->ovfmt = fmt;
+               btv->init.ovfmt = fmt;
+               if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+                       fh->ov.w.left   = 0;
+                       fh->ov.w.top    = 0;
+                       fh->ov.w.width  = fb->fmt.width;
+                       fh->ov.w.height = fb->fmt.height;
+                       btv->init.ov.w.width  = fb->fmt.width;
+                       btv->init.ov.w.height = fb->fmt.height;
+                               kfree(fh->ov.clips);
+                       fh->ov.clips = NULL;
+                       fh->ov.nclips = 0;
+
+                       if (check_btres(fh, RESOURCE_OVERLAY)) {
+                               struct bttv_buffer *new;
+
+                               new = videobuf_alloc(sizeof(*new));
+                               bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
+                               retval = bttv_switch_overlay(btv,fh,new);
+                       }
+               }
+               mutex_unlock(&fh->cap.lock);
+               return retval;
+       }
+
+       case VIDIOC_REQBUFS:
+               return videobuf_reqbufs(bttv_queue(fh),arg);
+
+       case VIDIOC_QUERYBUF:
+               return videobuf_querybuf(bttv_queue(fh),arg);
+
+       case VIDIOC_QBUF:
+               return videobuf_qbuf(bttv_queue(fh),arg);
+
+       case VIDIOC_DQBUF:
+               return videobuf_dqbuf(bttv_queue(fh),arg,
+                                     file->f_flags & O_NONBLOCK);
+
+       case VIDIOC_STREAMON:
+       {
+               int res = bttv_resource(fh);
+
+               if (!check_alloc_btres(btv,fh,res))
+                       return -EBUSY;
+               return videobuf_streamon(bttv_queue(fh));
+       }
+       case VIDIOC_STREAMOFF:
+       {
+               int res = bttv_resource(fh);
+
+               retval = videobuf_streamoff(bttv_queue(fh));
+               if (retval < 0)
+                       return retval;
+               free_btres(btv,fh,res);
+               return 0;
+       }
+
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *c = arg;
+               int i;
+
+               if ((c->id <  V4L2_CID_BASE ||
+                    c->id >= V4L2_CID_LASTP1) &&
+                   (c->id <  V4L2_CID_PRIVATE_BASE ||
+                    c->id >= V4L2_CID_PRIVATE_LASTP1))
+                       return -EINVAL;
+               for (i = 0; i < BTTV_CTLS; i++)
+                       if (bttv_ctls[i].id == c->id)
+                               break;
+               if (i == BTTV_CTLS) {
+                       *c = no_ctl;
+                       return 0;
+               }
+               *c = bttv_ctls[i];
+               if (i >= 4 && i <= 8) {
+                       struct video_audio va;
+                       memset(&va,0,sizeof(va));
+                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
+                       if (btv->audio_hook)
+                               btv->audio_hook(btv,&va,0);
+                       switch (bttv_ctls[i].id) {
+                       case V4L2_CID_AUDIO_VOLUME:
+                               if (!(va.flags & VIDEO_AUDIO_VOLUME))
+                                       *c = no_ctl;
+                               break;
+                       case V4L2_CID_AUDIO_BALANCE:
+                               if (!(va.flags & VIDEO_AUDIO_BALANCE))
+                                       *c = no_ctl;
+                               break;
+                       case V4L2_CID_AUDIO_BASS:
+                               if (!(va.flags & VIDEO_AUDIO_BASS))
+                                       *c = no_ctl;
+                               break;
+                       case V4L2_CID_AUDIO_TREBLE:
+                               if (!(va.flags & VIDEO_AUDIO_TREBLE))
+                                       *c = no_ctl;
+                               break;
+                       }
+               }
+               return 0;
+       }
+       case VIDIOC_G_CTRL:
+               return get_control(btv,arg);
+       case VIDIOC_S_CTRL:
+               return set_control(btv,arg);
+       case VIDIOC_G_PARM:
+       {
+               struct v4l2_streamparm *parm = arg;
+               struct v4l2_standard s;
+               if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               memset(parm,0,sizeof(*parm));
+               v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
+                                        bttv_tvnorms[btv->tvnorm].name);
+               parm->parm.capture.timeperframe = s.frameperiod;
+               return 0;
+       }
+
+       case VIDIOC_G_PRIORITY:
+       {
+               enum v4l2_priority *p = arg;
+
+               *p = v4l2_prio_max(&btv->prio);
+               return 0;
+       }
+       case VIDIOC_S_PRIORITY:
+       {
+               enum v4l2_priority *prio = arg;
+
+               return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
+       }
+
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_ENUMINPUT:
+       case VIDIOC_G_INPUT:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_G_TUNER:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_G_FREQUENCY:
+       case VIDIOC_S_FREQUENCY:
+       case VIDIOC_LOG_STATUS:
+               return bttv_common_ioctls(btv,cmd,arg);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+
+ fh_unlock_and_return:
+       mutex_unlock(&fh->cap.lock);
+       return retval;
+}
+
+static int bttv_ioctl(struct inode *inode, struct file *file,
+                     unsigned int cmd, unsigned long arg)
+{
+       struct bttv_fh *fh  = file->private_data;
+
+       switch (cmd) {
+       case BTTV_VBISIZE:
+               bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
+               return fh->lines * 2 * 2048;
+       default:
+               return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
+       }
+}
+
+static ssize_t bttv_read(struct file *file, char __user *data,
+                        size_t count, loff_t *ppos)
+{
+       struct bttv_fh *fh = file->private_data;
+       int retval = 0;
+
+       if (fh->btv->errors)
+               bttv_reinit_bt848(fh->btv);
+       dprintk("bttv%d: read count=%d type=%s\n",
+               fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (locked_btres(fh->btv,RESOURCE_VIDEO))
+                       return -EBUSY;
+               retval = videobuf_read_one(&fh->cap, data, count, ppos,
+                                          file->f_flags & O_NONBLOCK);
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+                       return -EBUSY;
+               retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
+                                             file->f_flags & O_NONBLOCK);
+               break;
+       default:
+               BUG();
+       }
+       return retval;
+}
+
+static unsigned int bttv_poll(struct file *file, poll_table *wait)
+{
+       struct bttv_fh *fh = file->private_data;
+       struct bttv_buffer *buf;
+       enum v4l2_field field;
+
+       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+               if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+                       return POLLERR;
+               return videobuf_poll_stream(file, &fh->vbi, wait);
+       }
+
+       if (check_btres(fh,RESOURCE_VIDEO)) {
+               /* streaming capture */
+               if (list_empty(&fh->cap.stream))
+                       return POLLERR;
+               buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
+       } else {
+               /* read() capture */
+               mutex_lock(&fh->cap.lock);
+               if (NULL == fh->cap.read_buf) {
+                       /* need to capture a new frame */
+                       if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
+                               mutex_unlock(&fh->cap.lock);
+                               return POLLERR;
+                       }
+                       fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
+                       if (NULL == fh->cap.read_buf) {
+                               mutex_unlock(&fh->cap.lock);
+                               return POLLERR;
+                       }
+                       fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
+                       field = videobuf_next_field(&fh->cap);
+                       if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
+                               kfree (fh->cap.read_buf);
+                               fh->cap.read_buf = NULL;
+                               mutex_unlock(&fh->cap.lock);
+                               return POLLERR;
+                       }
+                       fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+                       fh->cap.read_off = 0;
+               }
+               mutex_unlock(&fh->cap.lock);
+               buf = (struct bttv_buffer*)fh->cap.read_buf;
+       }
+
+       poll_wait(file, &buf->vb.done, wait);
+       if (buf->vb.state == STATE_DONE ||
+           buf->vb.state == STATE_ERROR)
+               return POLLIN|POLLRDNORM;
+       return 0;
+}
+
+static int bttv_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct bttv *btv = NULL;
+       struct bttv_fh *fh;
+       enum v4l2_buf_type type = 0;
+       unsigned int i;
+
+       dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
+
+       for (i = 0; i < bttv_num; i++) {
+               if (bttvs[i].video_dev &&
+                   bttvs[i].video_dev->minor == minor) {
+                       btv = &bttvs[i];
+                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       break;
+               }
+               if (bttvs[i].vbi_dev &&
+                   bttvs[i].vbi_dev->minor == minor) {
+                       btv = &bttvs[i];
+                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
+                       break;
+               }
+       }
+       if (NULL == btv)
+               return -ENODEV;
+
+       dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
+               btv->c.nr,v4l2_type_names[type]);
+
+       /* allocate per filehandle data */
+       fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+       file->private_data = fh;
+       *fh = btv->init;
+       fh->type = type;
+       fh->ov.setup_ok = 0;
+       v4l2_prio_open(&btv->prio,&fh->prio);
+
+       videobuf_queue_init(&fh->cap, &bttv_video_qops,
+                           btv->c.pci, &btv->s_lock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_INTERLACED,
+                           sizeof(struct bttv_buffer),
+                           fh);
+       videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
+                           btv->c.pci, &btv->s_lock,
+                           V4L2_BUF_TYPE_VBI_CAPTURE,
+                           V4L2_FIELD_SEQ_TB,
+                           sizeof(struct bttv_buffer),
+                           fh);
+       i2c_vidiocschan(btv);
+
+       btv->users++;
+       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
+               bttv_vbi_setlines(fh,btv,16);
+       bttv_field_count(btv);
+       return 0;
+}
+
+static int bttv_release(struct inode *inode, struct file *file)
+{
+       struct bttv_fh *fh = file->private_data;
+       struct bttv *btv = fh->btv;
+
+       /* turn off overlay */
+       if (check_btres(fh, RESOURCE_OVERLAY))
+               bttv_switch_overlay(btv,fh,NULL);
+
+       /* stop video capture */
+       if (check_btres(fh, RESOURCE_VIDEO)) {
+               videobuf_streamoff(&fh->cap);
+               free_btres(btv,fh,RESOURCE_VIDEO);
+       }
+       if (fh->cap.read_buf) {
+               buffer_release(&fh->cap,fh->cap.read_buf);
+               kfree(fh->cap.read_buf);
+       }
+
+       /* stop vbi capture */
+       if (check_btres(fh, RESOURCE_VBI)) {
+               if (fh->vbi.streaming)
+                       videobuf_streamoff(&fh->vbi);
+               if (fh->vbi.reading)
+                       videobuf_read_stop(&fh->vbi);
+               free_btres(btv,fh,RESOURCE_VBI);
+       }
+
+       /* free stuff */
+       videobuf_mmap_free(&fh->cap);
+       videobuf_mmap_free(&fh->vbi);
+       v4l2_prio_close(&btv->prio,&fh->prio);
+       file->private_data = NULL;
+       kfree(fh);
+
+       btv->users--;
+       bttv_field_count(btv);
+       return 0;
+}
+
+static int
+bttv_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct bttv_fh *fh = file->private_data;
+
+       dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
+               fh->btv->c.nr, v4l2_type_names[fh->type],
+               vma->vm_start, vma->vm_end - vma->vm_start);
+       return videobuf_mmap_mapper(bttv_queue(fh),vma);
+}
+
+static struct file_operations bttv_fops =
+{
+       .owner    = THIS_MODULE,
+       .open     = bttv_open,
+       .release  = bttv_release,
+       .ioctl    = bttv_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
+       .llseek   = no_llseek,
+       .read     = bttv_read,
+       .mmap     = bttv_mmap,
+       .poll     = bttv_poll,
+};
+
+static struct video_device bttv_video_template =
+{
+       .name     = "UNSET",
+       .type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
+                   VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+       .hardware = VID_HARDWARE_BT848,
+       .fops     = &bttv_fops,
+       .minor    = -1,
+};
+
+static struct video_device bttv_vbi_template =
+{
+       .name     = "bt848/878 vbi",
+       .type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
+       .hardware = VID_HARDWARE_BT848,
+       .fops     = &bttv_fops,
+       .minor    = -1,
+};
+
+/* ----------------------------------------------------------------------- */
+/* radio interface                                                         */
+
+static int radio_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct bttv *btv = NULL;
+       unsigned int i;
+
+       dprintk("bttv: open minor=%d\n",minor);
+
+       for (i = 0; i < bttv_num; i++) {
+               if (bttvs[i].radio_dev->minor == minor) {
+                       btv = &bttvs[i];
+                       break;
+               }
+       }
+       if (NULL == btv)
+               return -ENODEV;
+
+       dprintk("bttv%d: open called (radio)\n",btv->c.nr);
+       mutex_lock(&btv->lock);
+
+       btv->radio_user++;
+
+       file->private_data = btv;
+
+       bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
+       audio_input(btv,TVAUDIO_INPUT_RADIO);
+
+       mutex_unlock(&btv->lock);
+       return 0;
+}
+
+static int radio_release(struct inode *inode, struct file *file)
+{
+       struct bttv        *btv = file->private_data;
+       struct rds_command cmd;
+
+       btv->radio_user--;
+
+       bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
+
+       return 0;
+}
+
+static int radio_do_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, void *arg)
+{
+       struct bttv    *btv = file->private_data;
+
+       switch (cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability *cap = arg;
+
+               memset(cap,0,sizeof(*cap));
+               strcpy(cap->name,btv->radio_dev->name);
+               cap->type = VID_TYPE_TUNER;
+               cap->channels = 1;
+               cap->audios = 1;
+               return 0;
+       }
+
+       case VIDIOCGTUNER:
+       {
+               struct video_tuner *v = arg;
+
+               if(v->tuner)
+                       return -EINVAL;
+               memset(v,0,sizeof(*v));
+               strcpy(v->name, "Radio");
+               bttv_call_i2c_clients(btv,cmd,v);
+               return 0;
+       }
+       case VIDIOCSTUNER:
+               /* nothing to do */
+               return 0;
+
+       case BTTV_VERSION:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+       case VIDIOC_LOG_STATUS:
+               return bttv_common_ioctls(btv,cmd,arg);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int radio_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+}
+
+static ssize_t radio_read(struct file *file, char __user *data,
+                        size_t count, loff_t *ppos)
+{
+       struct bttv    *btv = file->private_data;
+       struct rds_command cmd;
+       cmd.block_count = count/3;
+       cmd.buffer = data;
+       cmd.instance = file;
+       cmd.result = -ENODEV;
+
+       bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
+
+       return cmd.result;
+}
+
+static unsigned int radio_poll(struct file *file, poll_table *wait)
+{
+       struct bttv    *btv = file->private_data;
+       struct rds_command cmd;
+       cmd.instance = file;
+       cmd.event_list = wait;
+       cmd.result = -ENODEV;
+       bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
+
+       return cmd.result;
+}
+
+static struct file_operations radio_fops =
+{
+       .owner    = THIS_MODULE,
+       .open     = radio_open,
+       .read     = radio_read,
+       .release  = radio_release,
+       .ioctl    = radio_ioctl,
+       .llseek   = no_llseek,
+       .poll     = radio_poll,
+};
+
+static struct video_device radio_template =
+{
+       .name     = "bt848/878 radio",
+       .type     = VID_TYPE_TUNER,
+       .hardware = VID_HARDWARE_BT848,
+       .fops     = &radio_fops,
+       .minor    = -1,
+};
+
+/* ----------------------------------------------------------------------- */
+/* some debug code                                                         */
+
+static int bttv_risc_decode(u32 risc)
+{
+       static char *instr[16] = {
+               [ BT848_RISC_WRITE     >> 28 ] = "write",
+               [ BT848_RISC_SKIP      >> 28 ] = "skip",
+               [ BT848_RISC_WRITEC    >> 28 ] = "writec",
+               [ BT848_RISC_JUMP      >> 28 ] = "jump",
+               [ BT848_RISC_SYNC      >> 28 ] = "sync",
+               [ BT848_RISC_WRITE123  >> 28 ] = "write123",
+               [ BT848_RISC_SKIP123   >> 28 ] = "skip123",
+               [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
+       };
+       static int incr[16] = {
+               [ BT848_RISC_WRITE     >> 28 ] = 2,
+               [ BT848_RISC_JUMP      >> 28 ] = 2,
+               [ BT848_RISC_SYNC      >> 28 ] = 2,
+               [ BT848_RISC_WRITE123  >> 28 ] = 5,
+               [ BT848_RISC_SKIP123   >> 28 ] = 2,
+               [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
+       };
+       static char *bits[] = {
+               "be0",  "be1",  "be2",  "be3/resync",
+               "set0", "set1", "set2", "set3",
+               "clr0", "clr1", "clr2", "clr3",
+               "irq",  "res",  "eol",  "sol",
+       };
+       int i;
+
+       printk("0x%08x [ %s", risc,
+              instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+       for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
+               if (risc & (1 << (i + 12)))
+                       printk(" %s",bits[i]);
+       printk(" count=%d ]\n", risc & 0xfff);
+       return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+static void bttv_risc_disasm(struct bttv *btv,
+                            struct btcx_riscmem *risc)
+{
+       unsigned int i,j,n;
+
+       printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+              btv->c.name, risc->cpu, (unsigned long)risc->dma);
+       for (i = 0; i < (risc->size >> 2); i += n) {
+               printk("%s:   0x%lx: ", btv->c.name,
+                      (unsigned long)(risc->dma + (i<<2)));
+               n = bttv_risc_decode(risc->cpu[i]);
+               for (j = 1; j < n; j++)
+                       printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
+                              btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
+                              risc->cpu[i+j], j);
+               if (0 == risc->cpu[i])
+                       break;
+       }
+}
+
+static void bttv_print_riscaddr(struct bttv *btv)
+{
+       printk("  main: %08Lx\n",
+              (unsigned long long)btv->main.dma);
+       printk("  vbi : o=%08Lx e=%08Lx\n",
+              btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
+              btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
+       printk("  cap : o=%08Lx e=%08Lx\n",
+              btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
+              btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
+       printk("  scr : o=%08Lx e=%08Lx\n",
+              btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
+              btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
+       bttv_risc_disasm(btv, &btv->main);
+}
+
+/* ----------------------------------------------------------------------- */
+/* irq handler                                                             */
+
+static char *irq_name[] = {
+       "FMTCHG",  // format change detected (525 vs. 625)
+       "VSYNC",   // vertical sync (new field)
+       "HSYNC",   // horizontal sync
+       "OFLOW",   // chroma/luma AGC overflow
+       "HLOCK",   // horizontal lock changed
+       "VPRES",   // video presence changed
+       "6", "7",
+       "I2CDONE", // hw irc operation finished
+       "GPINT",   // gpio port triggered irq
+       "10",
+       "RISCI",   // risc instruction triggered irq
+       "FBUS",    // pixel data fifo dropped data (high pci bus latencies)
+       "FTRGT",   // pixel data fifo overrun
+       "FDSR",    // fifo data stream resyncronisation
+       "PPERR",   // parity error (data transfer)
+       "RIPERR",  // parity error (read risc instructions)
+       "PABORT",  // pci abort
+       "OCERR",   // risc instruction error
+       "SCERR",   // syncronisation error
+};
+
+static void bttv_print_irqbits(u32 print, u32 mark)
+{
+       unsigned int i;
+
+       printk("bits:");
+       for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
+               if (print & (1 << i))
+                       printk(" %s",irq_name[i]);
+               if (mark & (1 << i))
+                       printk("*");
+       }
+}
+
+static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
+{
+       printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
+              btv->c.nr,
+              (unsigned long)btv->main.dma,
+              (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
+              (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
+              (unsigned long)rc);
+
+       if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
+               printk("bttv%d: Oh, there (temporarely?) is no input signal. "
+                      "Ok, then this is harmless, don't worry ;)\n",
+                      btv->c.nr);
+               return;
+       }
+       printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
+              btv->c.nr);
+       printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
+              btv->c.nr);
+       dump_stack();
+}
+
+static int
+bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
+{
+       struct bttv_buffer *item;
+
+       memset(set,0,sizeof(*set));
+
+       /* capture request ? */
+       if (!list_empty(&btv->capture)) {
+               set->frame_irq = 1;
+               item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
+               if (V4L2_FIELD_HAS_TOP(item->vb.field))
+                       set->top    = item;
+               if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
+                       set->bottom = item;
+
+               /* capture request for other field ? */
+               if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
+                   (item->vb.queue.next != &btv->capture)) {
+                       item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
+                       if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
+                               if (NULL == set->top &&
+                                   V4L2_FIELD_TOP == item->vb.field) {
+                                       set->top = item;
+                               }
+                               if (NULL == set->bottom &&
+                                   V4L2_FIELD_BOTTOM == item->vb.field) {
+                                       set->bottom = item;
+                               }
+                               if (NULL != set->top  &&  NULL != set->bottom)
+                                       set->top_irq = 2;
+                       }
+               }
+       }
+
+       /* screen overlay ? */
+       if (NULL != btv->screen) {
+               if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
+                       if (NULL == set->top && NULL == set->bottom) {
+                               set->top    = btv->screen;
+                               set->bottom = btv->screen;
+                       }
+               } else {
+                       if (V4L2_FIELD_TOP == btv->screen->vb.field &&
+                           NULL == set->top) {
+                               set->top = btv->screen;
+                       }
+                       if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
+                           NULL == set->bottom) {
+                               set->bottom = btv->screen;
+                       }
+               }
+       }
+
+       dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
+               btv->c.nr,set->top, set->bottom,
+               btv->screen,set->frame_irq,set->top_irq);
+       return 0;
+}
+
+static void
+bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
+                     struct bttv_buffer_set *curr, unsigned int state)
+{
+       struct timeval ts;
+
+       do_gettimeofday(&ts);
+
+       if (wakeup->top == wakeup->bottom) {
+               if (NULL != wakeup->top && curr->top != wakeup->top) {
+                       if (irq_debug > 1)
+                               printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
+                       wakeup->top->vb.ts = ts;
+                       wakeup->top->vb.field_count = btv->field_count;
+                       wakeup->top->vb.state = state;
+                       wake_up(&wakeup->top->vb.done);
+               }
+       } else {
+               if (NULL != wakeup->top && curr->top != wakeup->top) {
+                       if (irq_debug > 1)
+                               printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
+                       wakeup->top->vb.ts = ts;
+                       wakeup->top->vb.field_count = btv->field_count;
+                       wakeup->top->vb.state = state;
+                       wake_up(&wakeup->top->vb.done);
+               }
+               if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
+                       if (irq_debug > 1)
+                               printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
+                       wakeup->bottom->vb.ts = ts;
+                       wakeup->bottom->vb.field_count = btv->field_count;
+                       wakeup->bottom->vb.state = state;
+                       wake_up(&wakeup->bottom->vb.done);
+               }
+       }
+}
+
+static void
+bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
+                   unsigned int state)
+{
+       struct timeval ts;
+
+       if (NULL == wakeup)
+               return;
+
+       do_gettimeofday(&ts);
+       wakeup->vb.ts = ts;
+       wakeup->vb.field_count = btv->field_count;
+       wakeup->vb.state = state;
+       wake_up(&wakeup->vb.done);
+}
+
+static void bttv_irq_timeout(unsigned long data)
+{
+       struct bttv *btv = (struct bttv *)data;
+       struct bttv_buffer_set old,new;
+       struct bttv_buffer *ovbi;
+       struct bttv_buffer *item;
+       unsigned long flags;
+
+       if (bttv_verbose) {
+               printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
+                      btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
+                      btread(BT848_RISC_COUNT));
+               bttv_print_irqbits(btread(BT848_INT_STAT),0);
+               printk("\n");
+       }
+
+       spin_lock_irqsave(&btv->s_lock,flags);
+
+       /* deactivate stuff */
+       memset(&new,0,sizeof(new));
+       old  = btv->curr;
+       ovbi = btv->cvbi;
+       btv->curr = new;
+       btv->cvbi = NULL;
+       btv->loop_irq = 0;
+       bttv_buffer_activate_video(btv, &new);
+       bttv_buffer_activate_vbi(btv,   NULL);
+       bttv_set_dma(btv, 0);
+
+       /* wake up */
+       bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
+       bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
+
+       /* cancel all outstanding capture / vbi requests */
+       while (!list_empty(&btv->capture)) {
+               item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
+               list_del(&item->vb.queue);
+               item->vb.state = STATE_ERROR;
+               wake_up(&item->vb.done);
+       }
+       while (!list_empty(&btv->vcapture)) {
+               item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
+               list_del(&item->vb.queue);
+               item->vb.state = STATE_ERROR;
+               wake_up(&item->vb.done);
+       }
+
+       btv->errors++;
+       spin_unlock_irqrestore(&btv->s_lock,flags);
+}
+
+static void
+bttv_irq_wakeup_top(struct bttv *btv)
+{
+       struct bttv_buffer *wakeup = btv->curr.top;
+
+       if (NULL == wakeup)
+               return;
+
+       spin_lock(&btv->s_lock);
+       btv->curr.top_irq = 0;
+       btv->curr.top = NULL;
+       bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
+
+       do_gettimeofday(&wakeup->vb.ts);
+       wakeup->vb.field_count = btv->field_count;
+       wakeup->vb.state = STATE_DONE;
+       wake_up(&wakeup->vb.done);
+       spin_unlock(&btv->s_lock);
+}
+
+static inline int is_active(struct btcx_riscmem *risc, u32 rc)
+{
+       if (rc < risc->dma)
+               return 0;
+       if (rc > risc->dma + risc->size)
+               return 0;
+       return 1;
+}
+
+static void
+bttv_irq_switch_video(struct bttv *btv)
+{
+       struct bttv_buffer_set new;
+       struct bttv_buffer_set old;
+       dma_addr_t rc;
+
+       spin_lock(&btv->s_lock);
+
+       /* new buffer set */
+       bttv_irq_next_video(btv, &new);
+       rc = btread(BT848_RISC_COUNT);
+       if ((btv->curr.top    && is_active(&btv->curr.top->top,       rc)) ||
+           (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
+               btv->framedrop++;
+               if (debug_latency)
+                       bttv_irq_debug_low_latency(btv, rc);
+               spin_unlock(&btv->s_lock);
+               return;
+       }
+
+       /* switch over */
+       old = btv->curr;
+       btv->curr = new;
+       btv->loop_irq &= ~1;
+       bttv_buffer_activate_video(btv, &new);
+       bttv_set_dma(btv, 0);
+
+       /* switch input */
+       if (UNSET != btv->new_input) {
+               video_mux(btv,btv->new_input);
+               btv->new_input = UNSET;
+       }
+
+       /* wake up finished buffers */
+       bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
+       spin_unlock(&btv->s_lock);
+}
+
+static void
+bttv_irq_switch_vbi(struct bttv *btv)
+{
+       struct bttv_buffer *new = NULL;
+       struct bttv_buffer *old;
+       u32 rc;
+
+       spin_lock(&btv->s_lock);
+
+       if (!list_empty(&btv->vcapture))
+               new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
+       old = btv->cvbi;
+
+       rc = btread(BT848_RISC_COUNT);
+       if (NULL != old && (is_active(&old->top,    rc) ||
+                           is_active(&old->bottom, rc))) {
+               btv->framedrop++;
+               if (debug_latency)
+                       bttv_irq_debug_low_latency(btv, rc);
+               spin_unlock(&btv->s_lock);
+               return;
+       }
+
+       /* switch */
+       btv->cvbi = new;
+       btv->loop_irq &= ~4;
+       bttv_buffer_activate_vbi(btv, new);
+       bttv_set_dma(btv, 0);
+
+       bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
+       spin_unlock(&btv->s_lock);
+}
+
+static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
+{
+       u32 stat,astat;
+       u32 dstat;
+       int count;
+       struct bttv *btv;
+       int handled = 0;
+
+       btv=(struct bttv *)dev_id;
+
+       if (btv->custom_irq)
+               handled = btv->custom_irq(btv);
+
+       count=0;
+       while (1) {
+               /* get/clear interrupt status bits */
+               stat=btread(BT848_INT_STAT);
+               astat=stat&btread(BT848_INT_MASK);
+               if (!astat)
+                       break;
+               handled = 1;
+               btwrite(stat,BT848_INT_STAT);
+
+               /* get device status bits */
+               dstat=btread(BT848_DSTATUS);
+
+               if (irq_debug) {
+                       printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
+                              "riscs=%x, riscc=%08x, ",
+                              btv->c.nr, count, btv->field_count,
+                              stat>>28, btread(BT848_RISC_COUNT));
+                       bttv_print_irqbits(stat,astat);
+                       if (stat & BT848_INT_HLOCK)
+                               printk("   HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
+                                      ? "yes" : "no");
+                       if (stat & BT848_INT_VPRES)
+                               printk("   PRES => %s", (dstat & BT848_DSTATUS_PRES)
+                                      ? "yes" : "no");
+                       if (stat & BT848_INT_FMTCHG)
+                               printk("   NUML => %s", (dstat & BT848_DSTATUS_NUML)
+                                      ? "625" : "525");
+                       printk("\n");
+               }
+
+               if (astat&BT848_INT_VSYNC)
+                       btv->field_count++;
+
+               if ((astat & BT848_INT_GPINT) && btv->remote) {
+                       wake_up(&btv->gpioq);
+                       bttv_input_irq(btv);
+               }
+
+               if (astat & BT848_INT_I2CDONE) {
+                       btv->i2c_done = stat;
+                       wake_up(&btv->i2c_queue);
+               }
+
+               if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
+                       bttv_irq_switch_vbi(btv);
+
+               if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
+                       bttv_irq_wakeup_top(btv);
+
+               if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
+                       bttv_irq_switch_video(btv);
+
+               if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
+                       audio_mute(btv, btv->mute);  /* trigger automute */
+
+               if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
+                       printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
+                              (astat & BT848_INT_SCERR) ? "SCERR" : "",
+                              (astat & BT848_INT_OCERR) ? "OCERR" : "",
+                              btread(BT848_RISC_COUNT));
+                       bttv_print_irqbits(stat,astat);
+                       printk("\n");
+                       if (bttv_debug)
+                               bttv_print_riscaddr(btv);
+               }
+               if (fdsr && astat & BT848_INT_FDSR) {
+                       printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
+                              btv->c.nr,btread(BT848_RISC_COUNT));
+                       if (bttv_debug)
+                               bttv_print_riscaddr(btv);
+               }
+
+               count++;
+               if (count > 4) {
+
+                       if (count > 8 || !(astat & BT848_INT_GPINT)) {
+                               btwrite(0, BT848_INT_MASK);
+
+                               printk(KERN_ERR
+                                          "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+                       } else {
+                               printk(KERN_ERR
+                                          "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
+
+                               btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
+                                               BT848_INT_MASK);
+                       };
+
+                       bttv_print_irqbits(stat,astat);
+
+                       printk("]\n");
+               }
+       }
+       btv->irq_total++;
+       if (handled)
+               btv->irq_me++;
+       return IRQ_RETVAL(handled);
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* initialitation                                                          */
+
+static struct video_device *vdev_init(struct bttv *btv,
+                                     struct video_device *template,
+                                     char *type)
+{
+       struct video_device *vfd;
+
+       vfd = video_device_alloc();
+       if (NULL == vfd)
+               return NULL;
+       *vfd = *template;
+       vfd->minor   = -1;
+       vfd->dev     = &btv->c.pci->dev;
+       vfd->release = video_device_release;
+       snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
+                btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
+                type, bttv_tvcards[btv->c.type].name);
+       return vfd;
+}
+
+static void bttv_unregister_video(struct bttv *btv)
+{
+       if (btv->video_dev) {
+               if (-1 != btv->video_dev->minor)
+                       video_unregister_device(btv->video_dev);
+               else
+                       video_device_release(btv->video_dev);
+               btv->video_dev = NULL;
+       }
+       if (btv->vbi_dev) {
+               if (-1 != btv->vbi_dev->minor)
+                       video_unregister_device(btv->vbi_dev);
+               else
+                       video_device_release(btv->vbi_dev);
+               btv->vbi_dev = NULL;
+       }
+       if (btv->radio_dev) {
+               if (-1 != btv->radio_dev->minor)
+                       video_unregister_device(btv->radio_dev);
+               else
+                       video_device_release(btv->radio_dev);
+               btv->radio_dev = NULL;
+       }
+}
+
+/* register video4linux devices */
+static int __devinit bttv_register_video(struct bttv *btv)
+{
+       if (no_overlay <= 0) {
+               bttv_video_template.type |= VID_TYPE_OVERLAY;
+       } else {
+               printk("bttv: Overlay support disabled.\n");
+       }
+
+       /* video */
+       btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+       if (NULL == btv->video_dev)
+               goto err;
+       if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+               goto err;
+       printk(KERN_INFO "bttv%d: registered device video%d\n",
+              btv->c.nr,btv->video_dev->minor & 0x1f);
+       video_device_create_file(btv->video_dev, &class_device_attr_card);
+
+       /* vbi */
+       btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
+       if (NULL == btv->vbi_dev)
+               goto err;
+       if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+               goto err;
+       printk(KERN_INFO "bttv%d: registered device vbi%d\n",
+              btv->c.nr,btv->vbi_dev->minor & 0x1f);
+
+       if (!btv->has_radio)
+               return 0;
+       /* radio */
+       btv->radio_dev = vdev_init(btv, &radio_template, "radio");
+       if (NULL == btv->radio_dev)
+               goto err;
+       if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
+               goto err;
+       printk(KERN_INFO "bttv%d: registered device radio%d\n",
+              btv->c.nr,btv->radio_dev->minor & 0x1f);
+
+       /* all done */
+       return 0;
+
+ err:
+       bttv_unregister_video(btv);
+       return -1;
+}
+
+
+/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
+/* response on cards with no firmware is not enabled by OF */
+static void pci_set_command(struct pci_dev *dev)
+{
+#if defined(__powerpc__)
+       unsigned int cmd;
+
+       pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+       cmd = (cmd | PCI_COMMAND_MEMORY );
+       pci_write_config_dword(dev, PCI_COMMAND, cmd);
+#endif
+}
+
+static int __devinit bttv_probe(struct pci_dev *dev,
+                               const struct pci_device_id *pci_id)
+{
+       int result;
+       unsigned char lat;
+       struct bttv *btv;
+
+       if (bttv_num == BTTV_MAX)
+               return -ENOMEM;
+       printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
+       btv=&bttvs[bttv_num];
+       memset(btv,0,sizeof(*btv));
+       btv->c.nr  = bttv_num;
+       sprintf(btv->c.name,"bttv%d",btv->c.nr);
+
+       /* initialize structs / fill in defaults */
+       mutex_init(&btv->lock);
+       mutex_init(&btv->reslock);
+       spin_lock_init(&btv->s_lock);
+       spin_lock_init(&btv->gpio_lock);
+       init_waitqueue_head(&btv->gpioq);
+       init_waitqueue_head(&btv->i2c_queue);
+       INIT_LIST_HEAD(&btv->c.subs);
+       INIT_LIST_HEAD(&btv->capture);
+       INIT_LIST_HEAD(&btv->vcapture);
+       v4l2_prio_init(&btv->prio);
+
+       init_timer(&btv->timeout);
+       btv->timeout.function = bttv_irq_timeout;
+       btv->timeout.data     = (unsigned long)btv;
+
+       btv->i2c_rc = -1;
+       btv->tuner_type  = UNSET;
+       btv->new_input   = UNSET;
+       btv->has_radio=radio[btv->c.nr];
+
+       /* pci stuff (init, get irq/mmio, ... */
+       btv->c.pci = dev;
+       btv->id  = dev->device;
+       if (pci_enable_device(dev)) {
+               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+                      btv->c.nr);
+               return -EIO;
+       }
+       if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+               printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
+                      btv->c.nr);
+               return -EIO;
+       }
+       if (!request_mem_region(pci_resource_start(dev,0),
+                               pci_resource_len(dev,0),
+                               btv->c.name)) {
+               printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
+                      btv->c.nr, pci_resource_start(dev,0));
+               return -EBUSY;
+       }
+       pci_set_master(dev);
+       pci_set_command(dev);
+       pci_set_drvdata(dev,btv);
+
+       pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
+              bttv_num,btv->id, btv->revision, pci_name(dev));
+       printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+              btv->c.pci->irq, lat, pci_resource_start(dev,0));
+       schedule();
+
+       btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
+       if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
+               printk("bttv%d: ioremap() failed\n", btv->c.nr);
+               result = -EIO;
+               goto fail1;
+       }
+
+       /* identify card */
+       bttv_idcard(btv);
+
+       /* disable irqs, register irq handler */
+       btwrite(0, BT848_INT_MASK);
+       result = request_irq(btv->c.pci->irq, bttv_irq,
+                            SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+       if (result < 0) {
+               printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
+                      bttv_num,btv->c.pci->irq);
+               goto fail1;
+       }
+
+       if (0 != bttv_handle_chipset(btv)) {
+               result = -EIO;
+               goto fail2;
+       }
+
+       /* init options from insmod args */
+       btv->opt_combfilter = combfilter;
+       btv->opt_lumafilter = lumafilter;
+       btv->opt_automute   = automute;
+       btv->opt_chroma_agc = chroma_agc;
+       btv->opt_adc_crush  = adc_crush;
+       btv->opt_vcr_hack   = vcr_hack;
+       btv->opt_whitecrush_upper  = whitecrush_upper;
+       btv->opt_whitecrush_lower  = whitecrush_lower;
+       btv->opt_uv_ratio   = uv_ratio;
+       btv->opt_full_luma_range   = full_luma_range;
+       btv->opt_coring     = coring;
+
+       /* fill struct bttv with some useful defaults */
+       btv->init.btv         = btv;
+       btv->init.ov.w.width  = 320;
+       btv->init.ov.w.height = 240;
+       btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
+       btv->init.width       = 320;
+       btv->init.height      = 240;
+       btv->init.lines       = 16;
+       btv->input = 0;
+
+       /* initialize hardware */
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"pre-init");
+
+       bttv_risc_init_main(btv);
+       init_bt848(btv);
+
+       /* gpio */
+       btwrite(0x00, BT848_GPIO_REG_INP);
+       btwrite(0x00, BT848_GPIO_OUT_EN);
+       if (bttv_verbose)
+               bttv_gpio_tracking(btv,"init");
+
+       /* needs to be done before i2c is registered */
+       bttv_init_card1(btv);
+
+       /* register i2c + gpio */
+       init_bttv_i2c(btv);
+
+       /* some card-specific stuff (needs working i2c) */
+       bttv_init_card2(btv);
+       init_irqreg(btv);
+
+       /* register video4linux + input */
+       if (!bttv_tvcards[btv->c.type].no_video) {
+               bttv_register_video(btv);
+               bt848_bright(btv,32768);
+               bt848_contrast(btv,32768);
+               bt848_hue(btv,32768);
+               bt848_sat(btv,32768);
+               audio_mute(btv, 1);
+               set_input(btv,0);
+       }
+
+       /* add subdevices */
+       if (bttv_tvcards[btv->c.type].has_dvb)
+               bttv_sub_add_device(&btv->c, "dvb");
+
+       bttv_input_init(btv);
+
+       /* everything is fine */
+       bttv_num++;
+       return 0;
+
+ fail2:
+       free_irq(btv->c.pci->irq,btv);
+
+ fail1:
+       if (btv->bt848_mmio)
+               iounmap(btv->bt848_mmio);
+       release_mem_region(pci_resource_start(btv->c.pci,0),
+                          pci_resource_len(btv->c.pci,0));
+       pci_set_drvdata(dev,NULL);
+       return result;
+}
+
+static void __devexit bttv_remove(struct pci_dev *pci_dev)
+{
+       struct bttv *btv = pci_get_drvdata(pci_dev);
+
+       if (bttv_verbose)
+               printk("bttv%d: unloading\n",btv->c.nr);
+
+       /* shutdown everything (DMA+IRQs) */
+       btand(~15, BT848_GPIO_DMA_CTL);
+       btwrite(0, BT848_INT_MASK);
+       btwrite(~0x0, BT848_INT_STAT);
+       btwrite(0x0, BT848_GPIO_OUT_EN);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"cleanup");
+
+       /* tell gpio modules we are leaving ... */
+       btv->shutdown=1;
+       wake_up(&btv->gpioq);
+       bttv_input_fini(btv);
+       bttv_sub_del_devices(&btv->c);
+
+       /* unregister i2c_bus + input */
+       fini_bttv_i2c(btv);
+
+       /* unregister video4linux */
+       bttv_unregister_video(btv);
+
+       /* free allocated memory */
+       btcx_riscmem_free(btv->c.pci,&btv->main);
+
+       /* free ressources */
+       free_irq(btv->c.pci->irq,btv);
+       iounmap(btv->bt848_mmio);
+       release_mem_region(pci_resource_start(btv->c.pci,0),
+                          pci_resource_len(btv->c.pci,0));
+
+       pci_set_drvdata(pci_dev, NULL);
+       return;
+}
+
+static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+       struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct bttv_buffer_set idle;
+       unsigned long flags;
+
+       dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
+
+       /* stop dma + irqs */
+       spin_lock_irqsave(&btv->s_lock,flags);
+       memset(&idle, 0, sizeof(idle));
+       btv->state.video = btv->curr;
+       btv->state.vbi   = btv->cvbi;
+       btv->state.loop_irq = btv->loop_irq;
+       btv->curr = idle;
+       btv->loop_irq = 0;
+       bttv_buffer_activate_video(btv, &idle);
+       bttv_buffer_activate_vbi(btv, NULL);
+       bttv_set_dma(btv, 0);
+       btwrite(0, BT848_INT_MASK);
+       spin_unlock_irqrestore(&btv->s_lock,flags);
+
+       /* save bt878 state */
+       btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
+       btv->state.gpio_data   = gpio_read();
+
+       /* save pci state */
+       pci_save_state(pci_dev);
+       if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
+               pci_disable_device(pci_dev);
+               btv->state.disabled = 1;
+       }
+       return 0;
+}
+
+static int bttv_resume(struct pci_dev *pci_dev)
+{
+       struct bttv *btv = pci_get_drvdata(pci_dev);
+       unsigned long flags;
+       int err;
+
+       dprintk("bttv%d: resume\n", btv->c.nr);
+
+       /* restore pci state */
+       if (btv->state.disabled) {
+               err=pci_enable_device(pci_dev);
+               if (err) {
+                       printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+                                                               btv->c.nr);
+                       return err;
+               }
+               btv->state.disabled = 0;
+       }
+       err=pci_set_power_state(pci_dev, PCI_D0);
+       if (err) {
+               pci_disable_device(pci_dev);
+               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+                                                       btv->c.nr);
+               btv->state.disabled = 1;
+               return err;
+       }
+
+       pci_restore_state(pci_dev);
+
+       /* restore bt878 state */
+       bttv_reinit_bt848(btv);
+       gpio_inout(0xffffff, btv->state.gpio_enable);
+       gpio_write(btv->state.gpio_data);
+
+       /* restart dma */
+       spin_lock_irqsave(&btv->s_lock,flags);
+       btv->curr = btv->state.video;
+       btv->cvbi = btv->state.vbi;
+       btv->loop_irq = btv->state.loop_irq;
+       bttv_buffer_activate_video(btv, &btv->curr);
+       bttv_buffer_activate_vbi(btv, btv->cvbi);
+       bttv_set_dma(btv, 0);
+       spin_unlock_irqrestore(&btv->s_lock,flags);
+       return 0;
+}
+
+static struct pci_device_id bttv_pci_tbl[] = {
+       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
+
+static struct pci_driver bttv_pci_driver = {
+       .name     = "bttv",
+       .id_table = bttv_pci_tbl,
+       .probe    = bttv_probe,
+       .remove   = __devexit_p(bttv_remove),
+       .suspend  = bttv_suspend,
+       .resume   = bttv_resume,
+};
+
+static int bttv_init_module(void)
+{
+       bttv_num = 0;
+
+       printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
+              (BTTV_VERSION_CODE >> 16) & 0xff,
+              (BTTV_VERSION_CODE >> 8) & 0xff,
+              BTTV_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+       printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
+              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+       if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
+               gbuffers = 2;
+       if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+               gbufsize = BTTV_MAX_FBUF;
+       gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
+       if (bttv_verbose)
+               printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
+                      gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
+
+       bttv_check_chipset();
+
+       bus_register(&bttv_sub_bus_type);
+       return pci_register_driver(&bttv_pci_driver);
+}
+
+static void bttv_cleanup_module(void)
+{
+       pci_unregister_driver(&bttv_pci_driver);
+       bus_unregister(&bttv_sub_bus_type);
+       return;
+}
+
+module_init(bttv_init_module);
+module_exit(bttv_cleanup_module);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
new file mode 100644 (file)
index 0000000..c4d5e2b
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+
+    bttv-gpio.c  --  gpio sub drivers
+
+    sysfs-based sub driver interface for bttv
+    mainly intented for gpio access
+
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <asm/io.h>
+
+#include "bttvp.h"
+
+/* ----------------------------------------------------------------------- */
+/* internal: the bttv "bus"                                                */
+
+static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
+       int len = strlen(sub->wanted);
+
+       if (0 == strncmp(dev->bus_id, sub->wanted, len))
+               return 1;
+       return 0;
+}
+
+static int bttv_sub_probe(struct device *dev)
+{
+       struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+       struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+       return sub->probe ? sub->probe(sdev) : -ENODEV;
+}
+
+static int bttv_sub_remove(struct device *dev)
+{
+       struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+       struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+       if (sub->remove)
+               sub->remove(sdev);
+       return 0;
+}
+
+struct bus_type bttv_sub_bus_type = {
+       .name   = "bttv-sub",
+       .match  = &bttv_sub_bus_match,
+       .probe  = bttv_sub_probe,
+       .remove = bttv_sub_remove,
+};
+EXPORT_SYMBOL(bttv_sub_bus_type);
+
+static void release_sub_device(struct device *dev)
+{
+       struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
+       kfree(sub);
+}
+
+int bttv_sub_add_device(struct bttv_core *core, char *name)
+{
+       struct bttv_sub_device *sub;
+       int err;
+
+       sub = kzalloc(sizeof(*sub),GFP_KERNEL);
+       if (NULL == sub)
+               return -ENOMEM;
+
+       sub->core        = core;
+       sub->dev.parent  = &core->pci->dev;
+       sub->dev.bus     = &bttv_sub_bus_type;
+       sub->dev.release = release_sub_device;
+       snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
+                name, core->nr);
+
+       err = device_register(&sub->dev);
+       if (0 != err) {
+               kfree(sub);
+               return err;
+       }
+       printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
+       list_add_tail(&sub->list,&core->subs);
+       return 0;
+}
+
+int bttv_sub_del_devices(struct bttv_core *core)
+{
+       struct bttv_sub_device *sub;
+       struct list_head *item,*save;
+
+       list_for_each_safe(item,save,&core->subs) {
+               sub = list_entry(item,struct bttv_sub_device,list);
+               list_del(&sub->list);
+               device_unregister(&sub->dev);
+       }
+       return 0;
+}
+
+void bttv_gpio_irq(struct bttv_core *core)
+{
+       struct bttv_sub_driver *drv;
+       struct bttv_sub_device *dev;
+       struct list_head *item;
+
+       list_for_each(item,&core->subs) {
+               dev = list_entry(item,struct bttv_sub_device,list);
+               drv = to_bttv_sub_drv(dev->dev.driver);
+               if (drv && drv->gpio_irq)
+                       drv->gpio_irq(dev);
+       }
+}
+
+/* ----------------------------------------------------------------------- */
+/* external: sub-driver register/unregister                                */
+
+int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
+{
+       sub->drv.bus = &bttv_sub_bus_type;
+       snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
+       return driver_register(&sub->drv);
+}
+EXPORT_SYMBOL(bttv_sub_register);
+
+int bttv_sub_unregister(struct bttv_sub_driver *sub)
+{
+       driver_unregister(&sub->drv);
+       return 0;
+}
+EXPORT_SYMBOL(bttv_sub_unregister);
+
+/* ----------------------------------------------------------------------- */
+/* external: gpio access functions                                         */
+
+void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
+{
+       struct bttv *btv = container_of(core, struct bttv, c);
+       unsigned long flags;
+       u32 data;
+
+       spin_lock_irqsave(&btv->gpio_lock,flags);
+       data = btread(BT848_GPIO_OUT_EN);
+       data = data & ~mask;
+       data = data | (mask & outbits);
+       btwrite(data,BT848_GPIO_OUT_EN);
+       spin_unlock_irqrestore(&btv->gpio_lock,flags);
+}
+EXPORT_SYMBOL(bttv_gpio_inout);
+
+u32 bttv_gpio_read(struct bttv_core *core)
+{
+       struct bttv *btv = container_of(core, struct bttv, c);
+       u32 value;
+
+       value = btread(BT848_GPIO_DATA);
+       return value;
+}
+EXPORT_SYMBOL(bttv_gpio_read);
+
+void bttv_gpio_write(struct bttv_core *core, u32 value)
+{
+       struct bttv *btv = container_of(core, struct bttv, c);
+
+       btwrite(value,BT848_GPIO_DATA);
+}
+EXPORT_SYMBOL(bttv_gpio_write);
+
+void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
+{
+       struct bttv *btv = container_of(core, struct bttv, c);
+       unsigned long flags;
+       u32 data;
+
+       spin_lock_irqsave(&btv->gpio_lock,flags);
+       data = btread(BT848_GPIO_DATA);
+       data = data & ~mask;
+       data = data | (mask & bits);
+       btwrite(data,BT848_GPIO_DATA);
+       spin_unlock_irqrestore(&btv->gpio_lock,flags);
+}
+EXPORT_SYMBOL(bttv_gpio_bits);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
new file mode 100644 (file)
index 0000000..4b562b3
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+
+    bttv-i2c.c  --  all the i2c code is here
+
+    bttv - Bt848 frame grabber driver
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "bttvp.h"
+#include <media/v4l2-common.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
+
+static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
+static struct i2c_adapter bttv_i2c_adap_sw_template;
+static struct i2c_adapter bttv_i2c_adap_hw_template;
+static struct i2c_client bttv_i2c_client_template;
+
+static int attach_inform(struct i2c_client *client);
+
+static int i2c_debug;
+static int i2c_hw;
+static int i2c_scan;
+module_param(i2c_debug, int, 0644);
+module_param(i2c_hw,    int, 0444);
+module_param(i2c_scan,  int, 0444);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - bitbanging adapter (software i2c)                       */
+
+static void bttv_bit_setscl(void *data, int state)
+{
+       struct bttv *btv = (struct bttv*)data;
+
+       if (state)
+               btv->i2c_state |= 0x02;
+       else
+               btv->i2c_state &= ~0x02;
+       btwrite(btv->i2c_state, BT848_I2C);
+       btread(BT848_I2C);
+}
+
+static void bttv_bit_setsda(void *data, int state)
+{
+       struct bttv *btv = (struct bttv*)data;
+
+       if (state)
+               btv->i2c_state |= 0x01;
+       else
+               btv->i2c_state &= ~0x01;
+       btwrite(btv->i2c_state, BT848_I2C);
+       btread(BT848_I2C);
+}
+
+static int bttv_bit_getscl(void *data)
+{
+       struct bttv *btv = (struct bttv*)data;
+       int state;
+
+       state = btread(BT848_I2C) & 0x02 ? 1 : 0;
+       return state;
+}
+
+static int bttv_bit_getsda(void *data)
+{
+       struct bttv *btv = (struct bttv*)data;
+       int state;
+
+       state = btread(BT848_I2C) & 0x01;
+       return state;
+}
+
+static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
+       .setsda  = bttv_bit_setsda,
+       .setscl  = bttv_bit_setscl,
+       .getsda  = bttv_bit_getsda,
+       .getscl  = bttv_bit_getscl,
+       .udelay  = 16,
+       .mdelay  = 10,
+       .timeout = 200,
+};
+
+static struct i2c_adapter bttv_i2c_adap_sw_template = {
+       .owner             = THIS_MODULE,
+       .class             = I2C_CLASS_TV_ANALOG,
+       .name              = "bttv",
+       .id                = I2C_HW_B_BT848,
+       .client_register   = attach_inform,
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - hardware i2c                                            */
+
+static int algo_control(struct i2c_adapter *adapter,
+                       unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+bttv_i2c_wait_done(struct bttv *btv)
+{
+       int rc = 0;
+
+       /* timeout */
+       if (wait_event_interruptible_timeout(btv->i2c_queue,
+               btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
+
+       rc = -EIO;
+
+       if (btv->i2c_done & BT848_INT_RACK)
+               rc = 1;
+       btv->i2c_done = 0;
+       return rc;
+}
+
+#define I2C_HW (BT878_I2C_MODE  | BT848_I2C_SYNC |\
+               BT848_I2C_SCL | BT848_I2C_SDA)
+
+static int
+bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+{
+       u32 xmit;
+       int retval,cnt;
+
+       /* sanity checks */
+       if (0 == msg->len)
+               return -EINVAL;
+
+       /* start, address + first byte */
+       xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW;
+       if (msg->len > 1 || !last)
+               xmit |= BT878_I2C_NOSTOP;
+       btwrite(xmit, BT848_I2C);
+       retval = bttv_i2c_wait_done(btv);
+       if (retval < 0)
+               goto err;
+       if (retval == 0)
+               goto eio;
+       if (i2c_debug) {
+               printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+               if (!(xmit & BT878_I2C_NOSTOP))
+                       printk(" >\n");
+       }
+
+       for (cnt = 1; cnt < msg->len; cnt++ ) {
+               /* following bytes */
+               xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART;
+               if (cnt < msg->len-1 || !last)
+                       xmit |= BT878_I2C_NOSTOP;
+               btwrite(xmit, BT848_I2C);
+               retval = bttv_i2c_wait_done(btv);
+               if (retval < 0)
+                       goto err;
+               if (retval == 0)
+                       goto eio;
+               if (i2c_debug) {
+                       printk(" %02x", msg->buf[cnt]);
+                       if (!(xmit & BT878_I2C_NOSTOP))
+                               printk(" >\n");
+               }
+       }
+       return msg->len;
+
+ eio:
+       retval = -EIO;
+ err:
+       if (i2c_debug)
+               printk(" ERR: %d\n",retval);
+       return retval;
+}
+
+static int
+bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
+{
+       u32 xmit;
+       u32 cnt;
+       int retval;
+
+       for(cnt = 0; cnt < msg->len; cnt++) {
+               xmit = (msg->addr << 25) | (1 << 24) | I2C_HW;
+               if (cnt < msg->len-1)
+                       xmit |= BT848_I2C_W3B;
+               if (cnt < msg->len-1 || !last)
+                       xmit |= BT878_I2C_NOSTOP;
+               if (cnt)
+                       xmit |= BT878_I2C_NOSTART;
+               btwrite(xmit, BT848_I2C);
+               retval = bttv_i2c_wait_done(btv);
+               if (retval < 0)
+                       goto err;
+               if (retval == 0)
+                       goto eio;
+               msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff;
+               if (i2c_debug) {
+                       if (!(xmit & BT878_I2C_NOSTART))
+                               printk(" <R %02x", (msg->addr << 1) +1);
+                       printk(" =%02x", msg->buf[cnt]);
+                       if (!(xmit & BT878_I2C_NOSTOP))
+                               printk(" >\n");
+               }
+       }
+       return msg->len;
+
+ eio:
+       retval = -EIO;
+ err:
+       if (i2c_debug)
+               printk(" ERR: %d\n",retval);
+       return retval;
+}
+
+static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+       struct bttv *btv = i2c_get_adapdata(i2c_adap);
+       int retval = 0;
+       int i;
+
+       if (i2c_debug)
+               printk("bt-i2c:");
+       btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
+       for (i = 0 ; i < num; i++) {
+               if (msgs[i].flags & I2C_M_RD) {
+                       /* read */
+                       retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num);
+                       if (retval < 0)
+                               goto err;
+               } else {
+                       /* write */
+                       retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num);
+                       if (retval < 0)
+                               goto err;
+               }
+       }
+       return num;
+
+ err:
+       return retval;
+}
+
+static struct i2c_algorithm bttv_algo = {
+       .master_xfer   = bttv_i2c_xfer,
+       .algo_control  = algo_control,
+       .functionality = functionality,
+};
+
+static struct i2c_adapter bttv_i2c_adap_hw_template = {
+       .owner             = THIS_MODULE,
+       .class         = I2C_CLASS_TV_ANALOG,
+       .name          = "bt878",
+       .id            = I2C_HW_B_BT848 /* FIXME */,
+       .algo          = &bttv_algo,
+       .client_register = attach_inform,
+};
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions - common stuff                                            */
+
+static int attach_inform(struct i2c_client *client)
+{
+       struct bttv *btv = i2c_get_adapdata(client->adapter);
+       int addr=ADDR_UNSET;
+
+
+       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+               addr = bttv_tvcards[btv->c.type].tuner_addr;
+
+
+       if (bttv_debug)
+               printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
+                       btv->c.nr, client->driver->driver.name, client->addr,
+                       client->name);
+       if (!client->driver->command)
+               return 0;
+
+       if (client->driver->id == I2C_DRIVERID_MSP3400)
+               btv->i2c_msp34xx_client = client;
+       if (client->driver->id == I2C_DRIVERID_TVAUDIO)
+               btv->i2c_tvaudio_client = client;
+       if (btv->tuner_type != UNSET) {
+               struct tuner_setup tun_setup;
+
+               if ((addr==ADDR_UNSET) ||
+                               (addr==client->addr)) {
+
+                       tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
+                       tun_setup.type = btv->tuner_type;
+                       tun_setup.addr = addr;
+                       bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+               }
+
+       }
+
+       return 0;
+}
+
+void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
+{
+       if (0 != btv->i2c_rc)
+               return;
+       i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
+}
+
+static struct i2c_client bttv_i2c_client_template = {
+       .name   = "bttv internal",
+};
+
+
+/* read I2C */
+int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
+{
+       unsigned char buffer = 0;
+
+       if (0 != btv->i2c_rc)
+               return -1;
+       if (bttv_verbose && NULL != probe_for)
+               printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
+                      btv->c.nr,probe_for,addr);
+       btv->i2c_client.addr = addr >> 1;
+       if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+               if (NULL != probe_for) {
+                       if (bttv_verbose)
+                               printk("not found\n");
+               } else
+                       printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
+                              btv->c.nr,addr);
+               return -1;
+       }
+       if (bttv_verbose && NULL != probe_for)
+               printk("found\n");
+       return buffer;
+}
+
+/* write I2C */
+int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+                   unsigned char b2, int both)
+{
+       unsigned char buffer[2];
+       int bytes = both ? 2 : 1;
+
+       if (0 != btv->i2c_rc)
+               return -1;
+       btv->i2c_client.addr = addr >> 1;
+       buffer[0] = b1;
+       buffer[1] = b2;
+       if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+               return -1;
+       return 0;
+}
+
+/* read EEPROM content */
+void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
+{
+       memset(eedata, 0, 256);
+       if (0 != btv->i2c_rc)
+               return;
+       btv->i2c_client.addr = addr >> 1;
+       tveeprom_read(&btv->i2c_client, eedata, 256);
+}
+
+static char *i2c_devs[128] = {
+       [ 0x1c >> 1 ] = "lgdt330x",
+       [ 0x30 >> 1 ] = "IR (hauppauge)",
+       [ 0x80 >> 1 ] = "msp34xx",
+       [ 0x86 >> 1 ] = "tda9887",
+       [ 0xa0 >> 1 ] = "eeprom",
+       [ 0xc0 >> 1 ] = "tuner (analog)",
+       [ 0xc2 >> 1 ] = "tuner (analog)",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+       unsigned char buf;
+       int i,rc;
+
+       for (i = 0; i < 128; i++) {
+               c->addr = i;
+               rc = i2c_master_recv(c,&buf,0);
+               if (rc < 0)
+                       continue;
+               printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
+                      name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+       }
+}
+
+/* init + register i2c algo-bit adapter */
+int __devinit init_bttv_i2c(struct bttv *btv)
+{
+       memcpy(&btv->i2c_client, &bttv_i2c_client_template,
+              sizeof(bttv_i2c_client_template));
+
+       if (i2c_hw)
+               btv->use_i2c_hw = 1;
+       if (btv->use_i2c_hw) {
+               /* bt878 */
+               memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
+                      sizeof(bttv_i2c_adap_hw_template));
+       } else {
+               /* bt848 */
+               memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
+                      sizeof(bttv_i2c_adap_sw_template));
+               memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
+                      sizeof(bttv_i2c_algo_bit_template));
+               btv->i2c_algo.data = btv;
+               btv->c.i2c_adap.algo_data = &btv->i2c_algo;
+       }
+
+       btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
+       snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
+                "bt%d #%d [%s]", btv->id, btv->c.nr,
+                btv->use_i2c_hw ? "hw" : "sw");
+
+       i2c_set_adapdata(&btv->c.i2c_adap, btv);
+       btv->i2c_client.adapter = &btv->c.i2c_adap;
+
+       if (bttv_tvcards[btv->c.type].no_video)
+               btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
+       if (bttv_tvcards[btv->c.type].has_dvb)
+               btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
+
+       if (btv->use_i2c_hw) {
+               btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
+       } else {
+               bttv_bit_setscl(btv,1);
+               bttv_bit_setsda(btv,1);
+               btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap);
+       }
+       if (0 == btv->i2c_rc && i2c_scan)
+               do_i2c_scan(btv->c.name,&btv->i2c_client);
+       return btv->i2c_rc;
+}
+
+int __devexit fini_bttv_i2c(struct bttv *btv)
+{
+       if (0 != btv->i2c_rc)
+               return 0;
+
+       if (btv->use_i2c_hw) {
+               return i2c_del_adapter(&btv->c.i2c_adap);
+       } else {
+               return i2c_bit_del_bus(&btv->c.i2c_adap);
+       }
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/video/bt8xx/bttv-if.c
new file mode 100644 (file)
index 0000000..19b564a
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+
+    bttv-if.c  --  old gpio interface to other kernel modules
+                  don't use in new code, will go away in 2.7
+                  have a look at bttv-gpio.c instead.
+
+    bttv - Bt848 frame grabber driver
+
+    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "bttvp.h"
+
+EXPORT_SYMBOL(bttv_get_cardinfo);
+EXPORT_SYMBOL(bttv_get_pcidev);
+EXPORT_SYMBOL(bttv_get_id);
+EXPORT_SYMBOL(bttv_gpio_enable);
+EXPORT_SYMBOL(bttv_read_gpio);
+EXPORT_SYMBOL(bttv_write_gpio);
+EXPORT_SYMBOL(bttv_get_gpio_queue);
+EXPORT_SYMBOL(bttv_i2c_call);
+
+/* ----------------------------------------------------------------------- */
+/* Exported functions - for other modules which want to access the         */
+/*                      gpio ports (IR for example)                        */
+/*                      see bttv.h for comments                            */
+
+int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid)
+{
+       printk("The bttv_* interface is obsolete and will go away,\n"
+              "please use the new, sysfs based interface instead.\n");
+       if (card >= bttv_num) {
+               return -1;
+       }
+       *type   = bttvs[card].c.type;
+       *cardid = bttvs[card].cardid;
+       return 0;
+}
+
+struct pci_dev* bttv_get_pcidev(unsigned int card)
+{
+       if (card >= bttv_num)
+               return NULL;
+       return bttvs[card].c.pci;
+}
+
+int bttv_get_id(unsigned int card)
+{
+       printk("The bttv_* interface is obsolete and will go away,\n"
+              "please use the new, sysfs based interface instead.\n");
+       if (card >= bttv_num) {
+               return -1;
+       }
+       return bttvs[card].c.type;
+}
+
+
+int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
+{
+       struct bttv *btv;
+
+       if (card >= bttv_num) {
+               return -EINVAL;
+       }
+
+       btv = &bttvs[card];
+       gpio_inout(mask,data);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"extern enable");
+       return 0;
+}
+
+int bttv_read_gpio(unsigned int card, unsigned long *data)
+{
+       struct bttv *btv;
+
+       if (card >= bttv_num) {
+               return -EINVAL;
+       }
+
+       btv = &bttvs[card];
+
+       if(btv->shutdown) {
+               return -ENODEV;
+       }
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed
+   because we set direct input on init */
+       *data = gpio_read();
+       return 0;
+}
+
+int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
+{
+       struct bttv *btv;
+
+       if (card >= bttv_num) {
+               return -EINVAL;
+       }
+
+       btv = &bttvs[card];
+
+/* prior setting BT848_GPIO_REG_INP is (probably) not needed
+   because direct input is set on init */
+       gpio_bits(mask,data);
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"extern write");
+       return 0;
+}
+
+wait_queue_head_t* bttv_get_gpio_queue(unsigned int card)
+{
+       struct bttv *btv;
+
+       if (card >= bttv_num) {
+               return NULL;
+       }
+
+       btv = &bttvs[card];
+       if (bttvs[card].shutdown) {
+               return NULL;
+       }
+       return &btv->gpioq;
+}
+
+void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
+{
+       if (card >= bttv_num)
+               return;
+       bttv_call_i2c_clients(&bttvs[card], cmd, arg);
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
new file mode 100644 (file)
index 0000000..69efa0e
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ *
+ * Copyright (c) 2003 Gerd Knorr
+ * Copyright (c) 2003 Pavel Machek
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+
+#include "bttv.h"
+#include "bttvp.h"
+
+
+static int debug;
+module_param(debug, int, 0644);    /* debug level (0,1,2) */
+static int repeat_delay = 500;
+module_param(repeat_delay, int, 0644);
+static int repeat_period = 33;
+module_param(repeat_period, int, 0644);
+
+#define DEVNAME "bttv-input"
+
+/* ---------------------------------------------------------------------- */
+
+static void ir_handle_key(struct bttv *btv)
+{
+       struct bttv_ir *ir = btv->remote;
+       u32 gpio,data;
+
+       /* read gpio value */
+       gpio = bttv_gpio_read(&btv->c);
+       if (ir->polling) {
+               if (ir->last_gpio == gpio)
+                       return;
+               ir->last_gpio = gpio;
+       }
+
+       /* extract data */
+       data = ir_extract_bits(gpio, ir->mask_keycode);
+       dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
+               gpio, data,
+               ir->polling               ? "poll"  : "irq",
+               (gpio & ir->mask_keydown) ? " down" : "",
+               (gpio & ir->mask_keyup)   ? " up"   : "");
+
+       if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
+           (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
+               ir_input_keydown(ir->dev,&ir->ir,data,data);
+       } else {
+               ir_input_nokey(ir->dev,&ir->ir);
+       }
+
+}
+
+void bttv_input_irq(struct bttv *btv)
+{
+       struct bttv_ir *ir = btv->remote;
+
+       if (!ir->polling)
+               ir_handle_key(btv);
+}
+
+static void bttv_input_timer(unsigned long data)
+{
+       struct bttv *btv = (struct bttv*)data;
+       struct bttv_ir *ir = btv->remote;
+       unsigned long timeout;
+
+       ir_handle_key(btv);
+       timeout = jiffies + (ir->polling * HZ / 1000);
+       mod_timer(&ir->timer, timeout);
+}
+
+/* ---------------------------------------------------------------*/
+
+static int rc5_remote_gap = 885;
+module_param(rc5_remote_gap, int, 0644);
+static int rc5_key_timeout = 200;
+module_param(rc5_key_timeout, int, 0644);
+
+#define RC5_START(x)   (((x)>>12)&3)
+#define RC5_TOGGLE(x)  (((x)>>11)&1)
+#define RC5_ADDR(x)    (((x)>>6)&31)
+#define RC5_INSTR(x)   ((x)&63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 rc5_decode(unsigned int code)
+{
+       unsigned int org_code = code;
+       unsigned int pair;
+       unsigned int rc5 = 0;
+       int i;
+
+       code = (code << 1) | 1;
+       for (i = 0; i < 14; ++i) {
+               pair = code & 0x3;
+               code >>= 2;
+
+               rc5 <<= 1;
+               switch (pair) {
+               case 0:
+               case 2:
+                       break;
+               case 1:
+                       rc5 |= 1;
+                       break;
+               case 3:
+                       dprintk(KERN_WARNING "bad code: %x\n", org_code);
+                       return 0;
+               }
+       }
+       dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+               "instr=%x\n", rc5, org_code, RC5_START(rc5),
+               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+       return rc5;
+}
+
+static int bttv_rc5_irq(struct bttv *btv)
+{
+       struct bttv_ir *ir = btv->remote;
+       struct timeval tv;
+       u32 gpio;
+       u32 gap;
+       unsigned long current_jiffies, timeout;
+
+       /* read gpio port */
+       gpio = bttv_gpio_read(&btv->c);
+
+       /* remote IRQ? */
+       if (!(gpio & 0x20))
+               return 0;
+
+       /* get time of bit */
+       current_jiffies = jiffies;
+       do_gettimeofday(&tv);
+
+       /* avoid overflow with gap >1s */
+       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+               gap = 200000;
+       } else {
+               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+                   tv.tv_usec - ir->base_time.tv_usec;
+       }
+
+       /* active code => add bit */
+       if (ir->active) {
+               /* only if in the code (otherwise spurious IRQ or timer
+                  late) */
+               if (ir->last_bit < 28) {
+                       ir->last_bit = (gap - rc5_remote_gap / 2) /
+                           rc5_remote_gap;
+                       ir->code |= 1 << ir->last_bit;
+               }
+               /* starting new code */
+       } else {
+               ir->active = 1;
+               ir->code = 0;
+               ir->base_time = tv;
+               ir->last_bit = 0;
+
+               timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+               mod_timer(&ir->timer_end, timeout);
+       }
+
+       /* toggle GPIO pin 4 to reset the irq */
+       bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+       bttv_gpio_write(&btv->c, gpio | (1 << 4));
+       return 1;
+}
+
+
+static void bttv_rc5_timer_end(unsigned long data)
+{
+       struct bttv_ir *ir = (struct bttv_ir *)data;
+       struct timeval tv;
+       unsigned long current_jiffies, timeout;
+       u32 gap;
+
+       /* get time */
+       current_jiffies = jiffies;
+       do_gettimeofday(&tv);
+
+       /* avoid overflow with gap >1s */
+       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+               gap = 200000;
+       } else {
+               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+                   tv.tv_usec - ir->base_time.tv_usec;
+       }
+
+       /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+       if (gap < 28000) {
+               dprintk(KERN_WARNING "spurious timer_end\n");
+               return;
+       }
+
+       ir->active = 0;
+       if (ir->last_bit < 20) {
+               /* ignore spurious codes (caused by light/other remotes) */
+               dprintk(KERN_WARNING "short code: %x\n", ir->code);
+       } else {
+               u32 rc5 = rc5_decode(ir->code);
+
+               /* two start bits? */
+               if (RC5_START(rc5) != 3) {
+                       dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+                       /* right address? */
+               } else if (RC5_ADDR(rc5) == 0x0) {
+                       u32 toggle = RC5_TOGGLE(rc5);
+                       u32 instr = RC5_INSTR(rc5);
+
+                       /* Good code, decide if repeat/repress */
+                       if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+                           instr != RC5_INSTR(ir->last_rc5)) {
+                               dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
+                                       toggle);
+                               ir_input_nokey(ir->dev, &ir->ir);
+                               ir_input_keydown(ir->dev, &ir->ir, instr,
+                                                instr);
+                       }
+
+                       /* Set/reset key-up timer */
+                       timeout = current_jiffies + (500 + rc5_key_timeout
+                                                    * HZ) / 1000;
+                       mod_timer(&ir->timer_keyup, timeout);
+
+                       /* Save code for repeat test */
+                       ir->last_rc5 = rc5;
+               }
+       }
+}
+
+static void bttv_rc5_timer_keyup(unsigned long data)
+{
+       struct bttv_ir *ir = (struct bttv_ir *)data;
+
+       dprintk(KERN_DEBUG "key released\n");
+       ir_input_nokey(ir->dev, &ir->ir);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int bttv_input_init(struct bttv *btv)
+{
+       struct bttv_ir *ir;
+       IR_KEYTAB_TYPE *ir_codes = NULL;
+       struct input_dev *input_dev;
+       int ir_type = IR_TYPE_OTHER;
+
+       if (!btv->has_remote)
+               return -ENODEV;
+
+       ir = kzalloc(sizeof(*ir),GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ir || !input_dev) {
+               kfree(ir);
+               input_free_device(input_dev);
+               return -ENOMEM;
+       }
+       memset(ir,0,sizeof(*ir));
+
+       /* detect & configure */
+       switch (btv->c.type) {
+       case BTTV_BOARD_AVERMEDIA:
+       case BTTV_BOARD_AVPHONE98:
+       case BTTV_BOARD_AVERMEDIA98:
+               ir_codes         = ir_codes_avermedia;
+               ir->mask_keycode = 0xf88000;
+               ir->mask_keydown = 0x010000;
+               ir->polling      = 50; // ms
+               break;
+
+       case BTTV_BOARD_AVDVBT_761:
+       case BTTV_BOARD_AVDVBT_771:
+               ir_codes         = ir_codes_avermedia_dvbt;
+               ir->mask_keycode = 0x0f00c0;
+               ir->mask_keydown = 0x000020;
+               ir->polling      = 50; // ms
+               break;
+
+       case BTTV_BOARD_PXELVWPLTVPAK:
+               ir_codes         = ir_codes_pixelview;
+               ir->mask_keycode = 0x003e00;
+               ir->mask_keyup   = 0x010000;
+               ir->polling      = 50; // ms
+               break;
+       case BTTV_BOARD_PV_BT878P_9B:
+       case BTTV_BOARD_PV_BT878P_PLUS:
+               ir_codes         = ir_codes_pixelview;
+               ir->mask_keycode = 0x001f00;
+               ir->mask_keyup   = 0x008000;
+               ir->polling      = 50; // ms
+               break;
+
+       case BTTV_BOARD_WINFAST2000:
+               ir_codes         = ir_codes_winfast;
+               ir->mask_keycode = 0x1f8;
+               break;
+       case BTTV_BOARD_MAGICTVIEW061:
+       case BTTV_BOARD_MAGICTVIEW063:
+               ir_codes         = ir_codes_winfast;
+               ir->mask_keycode = 0x0008e000;
+               ir->mask_keydown = 0x00200000;
+               break;
+       case BTTV_BOARD_APAC_VIEWCOMP:
+               ir_codes         = ir_codes_apac_viewcomp;
+               ir->mask_keycode = 0x001f00;
+               ir->mask_keyup   = 0x008000;
+               ir->polling      = 50; // ms
+               break;
+       case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
+       case BTTV_BOARD_CONTVFMI:
+               ir_codes         = ir_codes_pixelview;
+               ir->mask_keycode = 0x001F00;
+               ir->mask_keyup   = 0x006000;
+               ir->polling      = 50; // ms
+               break;
+       case BTTV_BOARD_NEBULA_DIGITV:
+               ir_codes = ir_codes_nebula;
+               btv->custom_irq = bttv_rc5_irq;
+               ir->rc5_gpio = 1;
+               break;
+       case BTTV_BOARD_MACHTV_MAGICTV:
+               ir_codes         = ir_codes_apac_viewcomp;
+               ir->mask_keycode = 0x001F00;
+               ir->mask_keyup   = 0x004000;
+               ir->polling      = 50; /* ms */
+               break;
+       }
+       if (NULL == ir_codes) {
+               dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
+               kfree(ir);
+               input_free_device(input_dev);
+               return -ENODEV;
+       }
+
+       if (ir->rc5_gpio) {
+               u32 gpio;
+               /* enable remote irq */
+               bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
+               gpio = bttv_gpio_read(&btv->c);
+               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+               bttv_gpio_write(&btv->c, gpio | (1 << 4));
+       } else {
+               /* init hardware-specific stuff */
+               bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
+       }
+
+       /* init input device */
+       ir->dev = input_dev;
+
+       snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
+                btv->c.type);
+       snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+                pci_name(btv->c.pci));
+
+       ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
+       input_dev->name = ir->name;
+       input_dev->phys = ir->phys;
+       input_dev->id.bustype = BUS_PCI;
+       input_dev->id.version = 1;
+       if (btv->c.pci->subsystem_vendor) {
+               input_dev->id.vendor  = btv->c.pci->subsystem_vendor;
+               input_dev->id.product = btv->c.pci->subsystem_device;
+       } else {
+               input_dev->id.vendor  = btv->c.pci->vendor;
+               input_dev->id.product = btv->c.pci->device;
+       }
+       input_dev->cdev.dev = &btv->c.pci->dev;
+
+       btv->remote = ir;
+       if (ir->polling) {
+               init_timer(&ir->timer);
+               ir->timer.function = bttv_input_timer;
+               ir->timer.data     = (unsigned long)btv;
+               ir->timer.expires  = jiffies + HZ;
+               add_timer(&ir->timer);
+       } else if (ir->rc5_gpio) {
+               /* set timer_end for code completion */
+               init_timer(&ir->timer_end);
+               ir->timer_end.function = bttv_rc5_timer_end;
+               ir->timer_end.data = (unsigned long)ir;
+
+               init_timer(&ir->timer_keyup);
+               ir->timer_keyup.function = bttv_rc5_timer_keyup;
+               ir->timer_keyup.data = (unsigned long)ir;
+       }
+
+       /* all done */
+       input_register_device(btv->remote->dev);
+       printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+
+       /* the remote isn't as bouncy as a keyboard */
+       ir->dev->rep[REP_DELAY] = repeat_delay;
+       ir->dev->rep[REP_PERIOD] = repeat_period;
+
+       return 0;
+}
+
+void bttv_input_fini(struct bttv *btv)
+{
+       if (btv->remote == NULL)
+               return;
+
+       if (btv->remote->polling) {
+               del_timer_sync(&btv->remote->timer);
+               flush_scheduled_work();
+       }
+
+
+       if (btv->remote->rc5_gpio) {
+               u32 gpio;
+
+               del_timer_sync(&btv->remote->timer_end);
+               flush_scheduled_work();
+
+               gpio = bttv_gpio_read(&btv->c);
+               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+       }
+
+       input_unregister_device(btv->remote->dev);
+       kfree(btv->remote);
+       btv->remote = NULL;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
new file mode 100644 (file)
index 0000000..16323a5
--- /dev/null
@@ -0,0 +1,795 @@
+/*
+
+    bttv-risc.c  --  interfaces to other kernel modules
+
+    bttv risc code handling
+       - memory management
+       - generation
+
+    (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "bttvp.h"
+
+#define VCR_HACK_LINES 4
+
+/* ---------------------------------------------------------- */
+/* risc code generators                                       */
+
+int
+bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
+                struct scatterlist *sglist,
+                unsigned int offset, unsigned int bpl,
+                unsigned int padding, unsigned int lines)
+{
+       u32 instructions,line,todo;
+       struct scatterlist *sg;
+       u32 *rp;
+       int rc;
+
+       /* estimate risc mem: worst case is one write per page border +
+          one write per scan line + sync + jump (all 2 dwords).  padding
+          can cause next bpl to start close to a page border.  First DMA
+          region may be smaller than PAGE_SIZE */
+       instructions  = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
+       instructions += 2;
+       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
+               return rc;
+
+       /* sync instruction */
+       rp = risc->cpu;
+       *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+       *(rp++) = cpu_to_le32(0);
+
+       /* scan lines */
+       sg = sglist;
+       for (line = 0; line < lines; line++) {
+               if ((btv->opt_vcr_hack) &&
+                   (line >= (lines - VCR_HACK_LINES)))
+                       continue;
+               while (offset && offset >= sg_dma_len(sg)) {
+                       offset -= sg_dma_len(sg);
+                       sg++;
+               }
+               if (bpl <= sg_dma_len(sg)-offset) {
+                       /* fits into current chunk */
+                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+                                           BT848_RISC_EOL|bpl);
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+                       offset+=bpl;
+               } else {
+                       /* scanline needs to be splitted */
+                       todo = bpl;
+                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+                                           (sg_dma_len(sg)-offset));
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+                       todo -= (sg_dma_len(sg)-offset);
+                       offset = 0;
+                       sg++;
+                       while (todo > sg_dma_len(sg)) {
+                               *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
+                                                   sg_dma_len(sg));
+                               *(rp++)=cpu_to_le32(sg_dma_address(sg));
+                               todo -= sg_dma_len(sg);
+                               sg++;
+                       }
+                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
+                                           todo);
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg));
+                       offset += todo;
+               }
+               offset += padding;
+       }
+
+       /* save pointer to jmp instruction address */
+       risc->jmp = rp;
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+       return 0;
+}
+
+static int
+bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
+                struct scatterlist *sglist,
+                unsigned int yoffset,  unsigned int ybpl,
+                unsigned int ypadding, unsigned int ylines,
+                unsigned int uoffset,  unsigned int voffset,
+                unsigned int hshift,   unsigned int vshift,
+                unsigned int cpadding)
+{
+       unsigned int instructions,line,todo,ylen,chroma;
+       u32 *rp,ri;
+       struct scatterlist *ysg;
+       struct scatterlist *usg;
+       struct scatterlist *vsg;
+       int topfield = (0 == yoffset);
+       int rc;
+
+       /* estimate risc mem: worst case is one write per page border +
+          one write per scan line (5 dwords)
+          plus sync + jump (2 dwords) */
+       instructions  = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
+       instructions += 2;
+       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
+               return rc;
+
+       /* sync instruction */
+       rp = risc->cpu;
+       *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
+       *(rp++) = cpu_to_le32(0);
+
+       /* scan lines */
+       ysg = sglist;
+       usg = sglist;
+       vsg = sglist;
+       for (line = 0; line < ylines; line++) {
+               if ((btv->opt_vcr_hack) &&
+                   (line >= (ylines - VCR_HACK_LINES)))
+                       continue;
+               switch (vshift) {
+               case 0:
+                       chroma = 1;
+                       break;
+               case 1:
+                       if (topfield)
+                               chroma = ((line & 1) == 0);
+                       else
+                               chroma = ((line & 1) == 1);
+                       break;
+               case 2:
+                       if (topfield)
+                               chroma = ((line & 3) == 0);
+                       else
+                               chroma = ((line & 3) == 2);
+                       break;
+               default:
+                       chroma = 0;
+                       break;
+               }
+
+               for (todo = ybpl; todo > 0; todo -= ylen) {
+                       /* go to next sg entry if needed */
+                       while (yoffset && yoffset >= sg_dma_len(ysg)) {
+                               yoffset -= sg_dma_len(ysg);
+                               ysg++;
+                       }
+                       while (uoffset && uoffset >= sg_dma_len(usg)) {
+                               uoffset -= sg_dma_len(usg);
+                               usg++;
+                       }
+                       while (voffset && voffset >= sg_dma_len(vsg)) {
+                               voffset -= sg_dma_len(vsg);
+                               vsg++;
+                       }
+
+                       /* calculate max number of bytes we can write */
+                       ylen = todo;
+                       if (yoffset + ylen > sg_dma_len(ysg))
+                               ylen = sg_dma_len(ysg) - yoffset;
+                       if (chroma) {
+                               if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
+                                       ylen = (sg_dma_len(usg) - uoffset) << hshift;
+                               if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
+                                       ylen = (sg_dma_len(vsg) - voffset) << hshift;
+                               ri = BT848_RISC_WRITE123;
+                       } else {
+                               ri = BT848_RISC_WRITE1S23;
+                       }
+                       if (ybpl == todo)
+                               ri |= BT848_RISC_SOL;
+                       if (ylen == todo)
+                               ri |= BT848_RISC_EOL;
+
+                       /* write risc instruction */
+                       *(rp++)=cpu_to_le32(ri | ylen);
+                       *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
+                                           (ylen >> hshift));
+                       *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
+                       yoffset += ylen;
+                       if (chroma) {
+                               *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
+                               uoffset += ylen >> hshift;
+                               *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
+                               voffset += ylen >> hshift;
+                       }
+               }
+               yoffset += ypadding;
+               if (chroma) {
+                       uoffset += cpadding;
+                       voffset += cpadding;
+               }
+       }
+
+       /* save pointer to jmp instruction address */
+       risc->jmp = rp;
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+       return 0;
+}
+
+static int
+bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
+                 const struct bttv_format *fmt, struct bttv_overlay *ov,
+                 int skip_even, int skip_odd)
+{
+       int instructions,rc,line,maxy,start,end,skip,nskips;
+       struct btcx_skiplist *skips;
+       u32 *rp,ri,ra;
+       u32 addr;
+
+       /* skip list for window clipping */
+       if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
+               return -ENOMEM;
+
+       /* estimate risc mem: worst case is (clip+1) * lines instructions
+          + sync + jump (all 2 dwords) */
+       instructions  = (ov->nclips + 1) *
+               ((skip_even || skip_odd) ? ov->w.height>>1 :  ov->w.height);
+       instructions += 2;
+       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) {
+               kfree(skips);
+               return rc;
+       }
+
+       /* sync instruction */
+       rp = risc->cpu;
+       *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
+       *(rp++) = cpu_to_le32(0);
+
+       addr  = (unsigned long)btv->fbuf.base;
+       addr += btv->fbuf.fmt.bytesperline * ov->w.top;
+       addr += (fmt->depth >> 3)          * ov->w.left;
+
+       /* scan lines */
+       for (maxy = -1, line = 0; line < ov->w.height;
+            line++, addr += btv->fbuf.fmt.bytesperline) {
+               if ((btv->opt_vcr_hack) &&
+                    (line >= (ov->w.height - VCR_HACK_LINES)))
+                       continue;
+               if ((line%2) == 0  &&  skip_even)
+                       continue;
+               if ((line%2) == 1  &&  skip_odd)
+                       continue;
+
+               /* calculate clipping */
+               if (line > maxy)
+                       btcx_calc_skips(line, ov->w.width, &maxy,
+                                       skips, &nskips, ov->clips, ov->nclips);
+               else
+                       nskips = 0;
+
+               /* write out risc code */
+               for (start = 0, skip = 0; start < ov->w.width; start = end) {
+                       if (skip >= nskips) {
+                               ri  = BT848_RISC_WRITE;
+                               end = ov->w.width;
+                       } else if (start < skips[skip].start) {
+                               ri  = BT848_RISC_WRITE;
+                               end = skips[skip].start;
+                       } else {
+                               ri  = BT848_RISC_SKIP;
+                               end = skips[skip].end;
+                               skip++;
+                       }
+                       if (BT848_RISC_WRITE == ri)
+                               ra = addr + (fmt->depth>>3)*start;
+                       else
+                               ra = 0;
+
+                       if (0 == start)
+                               ri |= BT848_RISC_SOL;
+                       if (ov->w.width == end)
+                               ri |= BT848_RISC_EOL;
+                       ri |= (fmt->depth>>3) * (end-start);
+
+                       *(rp++)=cpu_to_le32(ri);
+                       if (0 != ra)
+                               *(rp++)=cpu_to_le32(ra);
+               }
+       }
+
+       /* save pointer to jmp instruction address */
+       risc->jmp = rp;
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+       kfree(skips);
+       return 0;
+}
+
+/* ---------------------------------------------------------- */
+
+static void
+bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
+             int width, int height, int interleaved, int norm)
+{
+       const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
+       u32 xsf, sr;
+       int vdelay;
+
+       int swidth       = tvnorm->swidth;
+       int totalwidth   = tvnorm->totalwidth;
+       int scaledtwidth = tvnorm->scaledtwidth;
+
+       if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+               swidth       = 720;
+               totalwidth   = 858;
+               scaledtwidth = 858;
+       }
+
+       vdelay = tvnorm->vdelay;
+
+       xsf = (width*scaledtwidth)/swidth;
+       geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
+       geo->hdelay =  tvnorm->hdelayx1;
+       geo->hdelay =  (geo->hdelay*width)/swidth;
+       geo->hdelay &= 0x3fe;
+       sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
+       geo->vscale =  (0x10000UL-sr) & 0x1fff;
+       geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
+               ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
+       geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
+       geo->vdelay  =  vdelay;
+       geo->width   =  width;
+       geo->sheight =  tvnorm->sheight;
+       geo->vtotal  =  tvnorm->vtotal;
+
+       if (btv->opt_combfilter) {
+               geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+               geo->comb = (width < 769) ? 1 : 0;
+       } else {
+               geo->vtc  = 0;
+               geo->comb = 0;
+       }
+}
+
+static void
+bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
+{
+       int off = odd ? 0x80 : 0x00;
+
+       if (geo->comb)
+               btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+       else
+               btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
+
+       btwrite(geo->vtc,             BT848_E_VTC+off);
+       btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
+       btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
+       btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
+       btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
+       btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
+       btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
+       btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
+       btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
+       btwrite(geo->crop,            BT848_E_CROP+off);
+       btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
+       btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
+}
+
+/* ---------------------------------------------------------- */
+/* risc group / risc main loop / dma management               */
+
+void
+bttv_set_dma(struct bttv *btv, int override)
+{
+       unsigned long cmd;
+       int capctl;
+
+       btv->cap_ctl = 0;
+       if (NULL != btv->curr.top)      btv->cap_ctl |= 0x02;
+       if (NULL != btv->curr.bottom)   btv->cap_ctl |= 0x01;
+       if (NULL != btv->cvbi)          btv->cap_ctl |= 0x0c;
+
+       capctl  = 0;
+       capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00;  /* capture  */
+       capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00;  /* vbi data */
+       capctl |= override;
+
+       d2printk(KERN_DEBUG
+                "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
+                btv->c.nr,capctl,btv->loop_irq,
+                btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
+                btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
+                btv->cvbi         ? (unsigned long long)btv->cvbi->bottom.dma         : 0,
+                btv->curr.bottom  ? (unsigned long long)btv->curr.bottom->bottom.dma  : 0);
+
+       cmd = BT848_RISC_JUMP;
+       if (btv->loop_irq) {
+               cmd |= BT848_RISC_IRQ;
+               cmd |= (btv->loop_irq  & 0x0f) << 16;
+               cmd |= (~btv->loop_irq & 0x0f) << 20;
+       }
+       if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
+               mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
+       } else {
+               del_timer(&btv->timeout);
+       }
+       btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
+
+       btaor(capctl, ~0x0f, BT848_CAP_CTL);
+       if (capctl) {
+               if (btv->dma_on)
+                       return;
+               btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
+               btor(3, BT848_GPIO_DMA_CTL);
+               btv->dma_on = 1;
+       } else {
+               if (!btv->dma_on)
+                       return;
+               btand(~3, BT848_GPIO_DMA_CTL);
+               btv->dma_on = 0;
+       }
+       return;
+}
+
+int
+bttv_risc_init_main(struct bttv *btv)
+{
+       int rc;
+
+       if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
+               return rc;
+       dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
+               btv->c.nr,(unsigned long long)btv->main.dma);
+
+       btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+                                      BT848_FIFO_STATUS_VRE);
+       btv->main.cpu[1] = cpu_to_le32(0);
+       btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
+
+       /* top field */
+       btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
+       btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
+
+       btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+                                      BT848_FIFO_STATUS_VRO);
+       btv->main.cpu[9] = cpu_to_le32(0);
+
+       /* bottom field */
+       btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
+       btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
+
+       /* jump back to top field */
+       btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
+
+       return 0;
+}
+
+int
+bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
+              int irqflags)
+{
+       unsigned long cmd;
+       unsigned long next = btv->main.dma + ((slot+2) << 2);
+
+       if (NULL == risc) {
+               d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
+                        btv->c.nr,risc,slot);
+               btv->main.cpu[slot+1] = cpu_to_le32(next);
+       } else {
+               d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
+                        btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
+               cmd = BT848_RISC_JUMP;
+               if (irqflags) {
+                       cmd |= BT848_RISC_IRQ;
+                       cmd |= (irqflags  & 0x0f) << 16;
+                       cmd |= (~irqflags & 0x0f) << 20;
+               }
+               risc->jmp[0] = cpu_to_le32(cmd);
+               risc->jmp[1] = cpu_to_le32(next);
+               btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
+       }
+       return 0;
+}
+
+void
+bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
+{
+       BUG_ON(in_interrupt());
+       videobuf_waiton(&buf->vb,0,0);
+       videobuf_dma_unmap(q, &buf->vb.dma);
+       videobuf_dma_free(&buf->vb.dma);
+       btcx_riscmem_free(btv->c.pci,&buf->bottom);
+       btcx_riscmem_free(btv->c.pci,&buf->top);
+       buf->vb.state = STATE_NEEDS_INIT;
+}
+
+int
+bttv_buffer_activate_vbi(struct bttv *btv,
+                        struct bttv_buffer *vbi)
+{
+       /* vbi capture */
+       if (vbi) {
+               vbi->vb.state = STATE_ACTIVE;
+               list_del(&vbi->vb.queue);
+               bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top,    0);
+               bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
+       } else {
+               bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
+               bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
+       }
+       return 0;
+}
+
+int
+bttv_buffer_activate_video(struct bttv *btv,
+                          struct bttv_buffer_set *set)
+{
+       /* video capture */
+       if (NULL != set->top  &&  NULL != set->bottom) {
+               if (set->top == set->bottom) {
+                       set->top->vb.state    = STATE_ACTIVE;
+                       if (set->top->vb.queue.next)
+                               list_del(&set->top->vb.queue);
+               } else {
+                       set->top->vb.state    = STATE_ACTIVE;
+                       set->bottom->vb.state = STATE_ACTIVE;
+                       if (set->top->vb.queue.next)
+                               list_del(&set->top->vb.queue);
+                       if (set->bottom->vb.queue.next)
+                               list_del(&set->bottom->vb.queue);
+               }
+               bttv_apply_geo(btv, &set->top->geo, 1);
+               bttv_apply_geo(btv, &set->bottom->geo,0);
+               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
+                              set->top_irq);
+               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
+                              set->frame_irq);
+               btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
+                     ~0xff, BT848_COLOR_FMT);
+               btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
+                     ~0x0f, BT848_COLOR_CTL);
+       } else if (NULL != set->top) {
+               set->top->vb.state  = STATE_ACTIVE;
+               if (set->top->vb.queue.next)
+                       list_del(&set->top->vb.queue);
+               bttv_apply_geo(btv, &set->top->geo,1);
+               bttv_apply_geo(btv, &set->top->geo,0);
+               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
+                              set->frame_irq);
+               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL,           0);
+               btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
+               btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
+       } else if (NULL != set->bottom) {
+               set->bottom->vb.state = STATE_ACTIVE;
+               if (set->bottom->vb.queue.next)
+                       list_del(&set->bottom->vb.queue);
+               bttv_apply_geo(btv, &set->bottom->geo,1);
+               bttv_apply_geo(btv, &set->bottom->geo,0);
+               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
+               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
+                              set->frame_irq);
+               btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
+               btaor(set->bottom->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
+       } else {
+               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
+               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
+       }
+       return 0;
+}
+
+/* ---------------------------------------------------------- */
+
+/* calculate geometry, build risc code */
+int
+bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
+{
+       const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
+
+       dprintk(KERN_DEBUG
+               "bttv%d: buffer field: %s  format: %s  size: %dx%d\n",
+               btv->c.nr, v4l2_field_names[buf->vb.field],
+               buf->fmt->name, buf->vb.width, buf->vb.height);
+
+       /* packed pixel modes */
+       if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
+               int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
+               int bpf = bpl * (buf->vb.height >> 1);
+
+               bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
+                             V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
+
+               switch (buf->vb.field) {
+               case V4L2_FIELD_TOP:
+                       bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+                                        0,bpl,0,buf->vb.height);
+                       break;
+               case V4L2_FIELD_BOTTOM:
+                       bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+                                        0,bpl,0,buf->vb.height);
+                       break;
+               case V4L2_FIELD_INTERLACED:
+                       bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+                                        0,bpl,bpl,buf->vb.height >> 1);
+                       bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+                                        bpl,bpl,bpl,buf->vb.height >> 1);
+                       break;
+               case V4L2_FIELD_SEQ_TB:
+                       bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+                                        0,bpl,0,buf->vb.height >> 1);
+                       bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+                                        bpf,bpl,0,buf->vb.height >> 1);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       /* planar modes */
+       if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
+               int uoffset, voffset;
+               int ypadding, cpadding, lines;
+
+               /* calculate chroma offsets */
+               uoffset = buf->vb.width * buf->vb.height;
+               voffset = buf->vb.width * buf->vb.height;
+               if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
+                       /* Y-Cr-Cb plane order */
+                       uoffset >>= buf->fmt->hshift;
+                       uoffset >>= buf->fmt->vshift;
+                       uoffset  += voffset;
+               } else {
+                       /* Y-Cb-Cr plane order */
+                       voffset >>= buf->fmt->hshift;
+                       voffset >>= buf->fmt->vshift;
+                       voffset  += uoffset;
+               }
+
+               switch (buf->vb.field) {
+               case V4L2_FIELD_TOP:
+                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+                                     buf->vb.height,0,buf->tvnorm);
+                       bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
+                                        0,buf->vb.width,0,buf->vb.height,
+                                        uoffset,voffset,buf->fmt->hshift,
+                                        buf->fmt->vshift,0);
+                       break;
+               case V4L2_FIELD_BOTTOM:
+                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+                                     buf->vb.height,0,buf->tvnorm);
+                       bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
+                                        0,buf->vb.width,0,buf->vb.height,
+                                        uoffset,voffset,buf->fmt->hshift,
+                                        buf->fmt->vshift,0);
+                       break;
+               case V4L2_FIELD_INTERLACED:
+                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+                                     buf->vb.height,1,buf->tvnorm);
+                       lines    = buf->vb.height >> 1;
+                       ypadding = buf->vb.width;
+                       cpadding = buf->vb.width >> buf->fmt->hshift;
+                       bttv_risc_planar(btv,&buf->top,
+                                        buf->vb.dma.sglist,
+                                        0,buf->vb.width,ypadding,lines,
+                                        uoffset,voffset,
+                                        buf->fmt->hshift,
+                                        buf->fmt->vshift,
+                                        cpadding);
+                       bttv_risc_planar(btv,&buf->bottom,
+                                        buf->vb.dma.sglist,
+                                        ypadding,buf->vb.width,ypadding,lines,
+                                        uoffset+cpadding,
+                                        voffset+cpadding,
+                                        buf->fmt->hshift,
+                                        buf->fmt->vshift,
+                                        cpadding);
+                       break;
+               case V4L2_FIELD_SEQ_TB:
+                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
+                                     buf->vb.height,1,buf->tvnorm);
+                       lines    = buf->vb.height >> 1;
+                       ypadding = buf->vb.width;
+                       cpadding = buf->vb.width >> buf->fmt->hshift;
+                       bttv_risc_planar(btv,&buf->top,
+                                        buf->vb.dma.sglist,
+                                        0,buf->vb.width,0,lines,
+                                        uoffset >> 1,
+                                        voffset >> 1,
+                                        buf->fmt->hshift,
+                                        buf->fmt->vshift,
+                                        0);
+                       bttv_risc_planar(btv,&buf->bottom,
+                                        buf->vb.dma.sglist,
+                                        lines * ypadding,buf->vb.width,0,lines,
+                                        lines * ypadding + (uoffset >> 1),
+                                        lines * ypadding + (voffset >> 1),
+                                        buf->fmt->hshift,
+                                        buf->fmt->vshift,
+                                        0);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       /* raw data */
+       if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
+               /* build risc code */
+               buf->vb.field = V4L2_FIELD_SEQ_TB;
+               bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
+                             1,buf->tvnorm);
+               bttv_risc_packed(btv, &buf->top,  buf->vb.dma.sglist,
+                                0, RAW_BPL, 0, RAW_LINES);
+               bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
+                                buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
+       }
+
+       /* copy format info */
+       buf->btformat = buf->fmt->btformat;
+       buf->btswap   = buf->fmt->btswap;
+       return 0;
+}
+
+/* ---------------------------------------------------------- */
+
+/* calculate geometry, build risc code */
+int
+bttv_overlay_risc(struct bttv *btv,
+                 struct bttv_overlay *ov,
+                 const struct bttv_format *fmt,
+                 struct bttv_buffer *buf)
+{
+       /* check interleave, bottom+top fields */
+       dprintk(KERN_DEBUG
+               "bttv%d: overlay fields: %s format: %s  size: %dx%d\n",
+               btv->c.nr, v4l2_field_names[buf->vb.field],
+               fmt->name,ov->w.width,ov->w.height);
+
+       /* calculate geometry */
+       bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
+                     V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
+
+       /* build risc code */
+       switch (ov->field) {
+       case V4L2_FIELD_TOP:
+               bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 0);
+               break;
+       case V4L2_FIELD_BOTTOM:
+               bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
+               break;
+       case V4L2_FIELD_INTERLACED:
+               bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 1);
+               bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
+               break;
+       default:
+               BUG();
+       }
+
+       /* copy format info */
+       buf->btformat = fmt->btformat;
+       buf->btswap   = fmt->btswap;
+       buf->vb.field = ov->field;
+       return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
new file mode 100644 (file)
index 0000000..e20ff23
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+
+    bttv - Bt848 frame grabber driver
+    vbi interface
+
+    (c) 2002 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include "bttvp.h"
+
+/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
+   bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
+   HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
+   of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
+#define VBI_OFFSET ((64 + 0) * 2)
+
+#define VBI_DEFLINES 16
+#define VBI_MAXLINES 32
+
+static unsigned int vbibufs = 4;
+static unsigned int vbi_debug = 0;
+
+module_param(vbibufs,   int, 0444);
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");
+MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
+
+#ifdef dprintk
+# undef dprintk
+#endif
+#define dprintk(fmt, arg...)   if (vbi_debug) \
+       printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
+
+/* ----------------------------------------------------------------------- */
+/* vbi risc code + mm                                                      */
+
+static int
+vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
+{
+       int bpl = 2048;
+
+       bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
+                        0, bpl-4, 4, lines);
+       bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
+                        lines * bpl, bpl-4, 4, lines);
+       return 0;
+}
+
+static int vbi_buffer_setup(struct videobuf_queue *q,
+                           unsigned int *count, unsigned int *size)
+{
+       struct bttv_fh *fh = q->priv_data;
+       struct bttv *btv = fh->btv;
+
+       if (0 == *count)
+               *count = vbibufs;
+       *size = fh->lines * 2 * 2048;
+       dprintk("setup: lines=%d\n",fh->lines);
+       return 0;
+}
+
+static int vbi_buffer_prepare(struct videobuf_queue *q,
+                             struct videobuf_buffer *vb,
+                             enum v4l2_field field)
+{
+       struct bttv_fh *fh = q->priv_data;
+       struct bttv *btv = fh->btv;
+       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+       int rc;
+
+       buf->vb.size = fh->lines * 2 * 2048;
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       if (STATE_NEEDS_INIT == buf->vb.state) {
+               if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+                       goto fail;
+               if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
+                       goto fail;
+       }
+       buf->vb.state = STATE_PREPARED;
+       buf->vb.field = field;
+       dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
+               vb, &buf->top, &buf->bottom,
+               v4l2_field_names[buf->vb.field]);
+       return 0;
+
+ fail:
+       bttv_dma_free(q,btv,buf);
+       return rc;
+}
+
+static void
+vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct bttv_fh *fh = q->priv_data;
+       struct bttv *btv = fh->btv;
+       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+
+       dprintk("queue %p\n",vb);
+       buf->vb.state = STATE_QUEUED;
+       list_add_tail(&buf->vb.queue,&btv->vcapture);
+       if (NULL == btv->cvbi) {
+               fh->btv->loop_irq |= 4;
+               bttv_set_dma(btv,0x0c);
+       }
+}
+
+static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct bttv_fh *fh = q->priv_data;
+       struct bttv *btv = fh->btv;
+       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+
+       dprintk("free %p\n",vb);
+       bttv_dma_free(&fh->cap,fh->btv,buf);
+}
+
+struct videobuf_queue_ops bttv_vbi_qops = {
+       .buf_setup    = vbi_buffer_setup,
+       .buf_prepare  = vbi_buffer_prepare,
+       .buf_queue    = vbi_buffer_queue,
+       .buf_release  = vbi_buffer_release,
+};
+
+/* ----------------------------------------------------------------------- */
+
+void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
+{
+       int vdelay;
+
+       if (lines < 1)
+               lines = 1;
+       if (lines > VBI_MAXLINES)
+               lines = VBI_MAXLINES;
+       fh->lines = lines;
+
+       vdelay = btread(BT848_E_VDELAY_LO);
+       if (vdelay < lines*2) {
+               vdelay = lines*2;
+               btwrite(vdelay,BT848_E_VDELAY_LO);
+               btwrite(vdelay,BT848_O_VDELAY_LO);
+       }
+}
+
+void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+{
+       const struct bttv_tvnorm *tvnorm;
+       s64 count0,count1,count;
+
+       tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
+       f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
+       f->fmt.vbi.samples_per_line = 2048;
+       f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
+       f->fmt.vbi.offset           = VBI_OFFSET;
+       f->fmt.vbi.flags            = 0;
+
+       /* s64 to prevent overflow. */
+       count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
+               - tvnorm->vbistart[0];
+       count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
+               - tvnorm->vbistart[1];
+       count  = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
+
+       f->fmt.vbi.start[0] = tvnorm->vbistart[0];
+       f->fmt.vbi.start[1] = tvnorm->vbistart[1];
+       f->fmt.vbi.count[0] = count;
+       f->fmt.vbi.count[1] = count;
+
+       f->fmt.vbi.reserved[0] = 0;
+       f->fmt.vbi.reserved[1] = 0;
+}
+
+void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+{
+       const struct bttv_tvnorm *tvnorm;
+
+       tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
+       memset(f,0,sizeof(*f));
+       f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
+       f->fmt.vbi.samples_per_line = 2048;
+       f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
+       f->fmt.vbi.offset           = VBI_OFFSET;
+       f->fmt.vbi.start[0]         = tvnorm->vbistart[0];
+       f->fmt.vbi.start[1]         = tvnorm->vbistart[1];
+       f->fmt.vbi.count[0]         = fh->lines;
+       f->fmt.vbi.count[1]         = fh->lines;
+       f->fmt.vbi.flags            = 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
new file mode 100644 (file)
index 0000000..3a23265
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ *
+ *  bttv - Bt848 frame grabber driver
+ *
+ *  card ID's and external interfaces of the bttv driver
+ *  basically stuff needed by other drivers (i2c, lirc, ...)
+ *  and is supported not to change much over time.
+ *
+ *  Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ *  (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#ifndef _BTTV_H_
+#define _BTTV_H_
+
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
+#include <media/i2c-addr.h>
+
+/* ---------------------------------------------------------- */
+/* exported by bttv-cards.c                                   */
+
+#define BTTV_BOARD_UNKNOWN                 0x00
+#define BTTV_BOARD_MIRO                    0x01
+#define BTTV_BOARD_HAUPPAUGE               0x02
+#define BTTV_BOARD_STB                     0x03
+#define BTTV_BOARD_INTEL                   0x04
+#define BTTV_BOARD_DIAMOND                 0x05
+#define BTTV_BOARD_AVERMEDIA               0x06
+#define BTTV_BOARD_MATRIX_VISION           0x07
+#define BTTV_BOARD_FLYVIDEO                0x08
+#define BTTV_BOARD_TURBOTV                 0x09
+#define BTTV_BOARD_HAUPPAUGE878            0x0a
+#define BTTV_BOARD_MIROPRO                 0x0b
+#define BTTV_BOARD_ADSTECH_TV              0x0c
+#define BTTV_BOARD_AVERMEDIA98             0x0d
+#define BTTV_BOARD_VHX                     0x0e
+#define BTTV_BOARD_ZOLTRIX                 0x0f
+#define BTTV_BOARD_PIXVIEWPLAYTV           0x10
+#define BTTV_BOARD_WINVIEW_601             0x11
+#define BTTV_BOARD_AVEC_INTERCAP           0x12
+#define BTTV_BOARD_LIFE_FLYKIT             0x13
+#define BTTV_BOARD_CEI_RAFFLES             0x14
+#define BTTV_BOARD_CONFERENCETV            0x15
+#define BTTV_BOARD_PHOEBE_TVMAS            0x16
+#define BTTV_BOARD_MODTEC_205              0x17
+#define BTTV_BOARD_MAGICTVIEW061           0x18
+#define BTTV_BOARD_VOBIS_BOOSTAR           0x19
+#define BTTV_BOARD_HAUPPAUG_WCAM           0x1a
+#define BTTV_BOARD_MAXI                    0x1b
+#define BTTV_BOARD_TERRATV                 0x1c
+#define BTTV_BOARD_PXC200                  0x1d
+#define BTTV_BOARD_FLYVIDEO_98             0x1e
+#define BTTV_BOARD_IPROTV                  0x1f
+#define BTTV_BOARD_INTEL_C_S_PCI           0x20
+#define BTTV_BOARD_TERRATVALUE             0x21
+#define BTTV_BOARD_WINFAST2000             0x22
+#define BTTV_BOARD_CHRONOS_VS2             0x23
+#define BTTV_BOARD_TYPHOON_TVIEW           0x24
+#define BTTV_BOARD_PXELVWPLTVPRO           0x25
+#define BTTV_BOARD_MAGICTVIEW063           0x26
+#define BTTV_BOARD_PINNACLE                0x27
+#define BTTV_BOARD_STB2                    0x28
+#define BTTV_BOARD_AVPHONE98               0x29
+#define BTTV_BOARD_PV951                   0x2a
+#define BTTV_BOARD_ONAIR_TV                0x2b
+#define BTTV_BOARD_SIGMA_TVII_FM           0x2c
+#define BTTV_BOARD_MATRIX_VISION2          0x2d
+#define BTTV_BOARD_ZOLTRIX_GENIE           0x2e
+#define BTTV_BOARD_TERRATVRADIO            0x2f
+#define BTTV_BOARD_DYNALINK                0x30
+#define BTTV_BOARD_GVBCTV3PCI              0x31
+#define BTTV_BOARD_PXELVWPLTVPAK           0x32
+#define BTTV_BOARD_EAGLE                   0x33
+#define BTTV_BOARD_PINNACLEPRO             0x34
+#define BTTV_BOARD_TVIEW_RDS_FM            0x35
+#define BTTV_BOARD_LIFETEC_9415            0x36
+#define BTTV_BOARD_BESTBUY_EASYTV          0x37
+#define BTTV_BOARD_FLYVIDEO_98FM           0x38
+#define BTTV_BOARD_GRANDTEC                0x39
+#define BTTV_BOARD_ASKEY_CPH060            0x3a
+#define BTTV_BOARD_ASKEY_CPH03X            0x3b
+#define BTTV_BOARD_MM100PCTV               0x3c
+#define BTTV_BOARD_GMV1                    0x3d
+#define BTTV_BOARD_BESTBUY_EASYTV2         0x3e
+#define BTTV_BOARD_ATI_TVWONDER            0x3f
+#define BTTV_BOARD_ATI_TVWONDERVE          0x40
+#define BTTV_BOARD_FLYVIDEO2000            0x41
+#define BTTV_BOARD_TERRATVALUER            0x42
+#define BTTV_BOARD_GVBCTV4PCI              0x43
+#define BTTV_BOARD_VOODOOTV_FM             0x44
+#define BTTV_BOARD_AIMMS                   0x45
+#define BTTV_BOARD_PV_BT878P_PLUS          0x46
+#define BTTV_BOARD_FLYVIDEO98EZ            0x47
+#define BTTV_BOARD_PV_BT878P_9B            0x48
+#define BTTV_BOARD_SENSORAY311             0x49
+#define BTTV_BOARD_RV605                   0x4a
+#define BTTV_BOARD_POWERCLR_MTV878         0x4b
+#define BTTV_BOARD_WINDVR                  0x4c
+#define BTTV_BOARD_GRANDTEC_MULTI          0x4d
+#define BTTV_BOARD_KWORLD                  0x4e
+#define BTTV_BOARD_DSP_TCVIDEO             0x4f
+#define BTTV_BOARD_HAUPPAUGEPVR            0x50
+#define BTTV_BOARD_GVBCTV5PCI              0x51
+#define BTTV_BOARD_OSPREY1x0               0x52
+#define BTTV_BOARD_OSPREY1x0_848           0x53
+#define BTTV_BOARD_OSPREY101_848           0x54
+#define BTTV_BOARD_OSPREY1x1               0x55
+#define BTTV_BOARD_OSPREY1x1_SVID          0x56
+#define BTTV_BOARD_OSPREY2xx               0x57
+#define BTTV_BOARD_OSPREY2x0_SVID          0x58
+#define BTTV_BOARD_OSPREY2x0               0x59
+#define BTTV_BOARD_OSPREY500               0x5a
+#define BTTV_BOARD_OSPREY540               0x5b
+#define BTTV_BOARD_OSPREY2000              0x5c
+#define BTTV_BOARD_IDS_EAGLE               0x5d
+#define BTTV_BOARD_PINNACLESAT             0x5e
+#define BTTV_BOARD_FORMAC_PROTV            0x5f
+#define BTTV_BOARD_MACHTV                  0x60
+#define BTTV_BOARD_EURESYS_PICOLO          0x61
+#define BTTV_BOARD_PV150                   0x62
+#define BTTV_BOARD_AD_TVK503               0x63
+#define BTTV_BOARD_HERCULES_SM_TV          0x64
+#define BTTV_BOARD_PACETV                  0x65
+#define BTTV_BOARD_IVC200                  0x66
+#define BTTV_BOARD_XGUARD                  0x67
+#define BTTV_BOARD_NEBULA_DIGITV           0x68
+#define BTTV_BOARD_PV143                   0x69
+#define BTTV_BOARD_VD009X1_MINIDIN         0x6a
+#define BTTV_BOARD_VD009X1_COMBI           0x6b
+#define BTTV_BOARD_VD009_MINIDIN           0x6c
+#define BTTV_BOARD_VD009_COMBI             0x6d
+#define BTTV_BOARD_IVC100                  0x6e
+#define BTTV_BOARD_IVC120                  0x6f
+#define BTTV_BOARD_PC_HDTV                 0x70
+#define BTTV_BOARD_TWINHAN_DST             0x71
+#define BTTV_BOARD_WINFASTVC100            0x72
+#define BTTV_BOARD_TEV560                  0x73
+#define BTTV_BOARD_SIMUS_GVC1100           0x74
+#define BTTV_BOARD_NGSTV_PLUS              0x75
+#define BTTV_BOARD_LMLBT4                  0x76
+#define BTTV_BOARD_TEKRAM_M205             0x77
+#define BTTV_BOARD_CONTVFMI                0x78
+#define BTTV_BOARD_PICOLO_TETRA_CHIP       0x79
+#define BTTV_BOARD_SPIRIT_TV               0x7a
+#define BTTV_BOARD_AVDVBT_771              0x7b
+#define BTTV_BOARD_AVDVBT_761              0x7c
+#define BTTV_BOARD_MATRIX_VISIONSQ         0x7d
+#define BTTV_BOARD_MATRIX_VISIONSLC        0x7e
+#define BTTV_BOARD_APAC_VIEWCOMP           0x7f
+#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
+#define BTTV_BOARD_VGEAR_MYVCD             0x81
+#define BTTV_BOARD_SUPER_TV                0x82
+#define BTTV_BOARD_TIBET_CS16              0x83
+#define BTTV_BOARD_KODICOM_4400R           0x84
+#define BTTV_BOARD_KODICOM_4400R_SL        0x85
+#define BTTV_BOARD_ADLINK_RTV24            0x86
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+#define BTTV_BOARD_ACORP_Y878F             0x88
+#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2    0x89
+#define BTTV_BOARD_PV_BT878P_2E            0x8a
+#define BTTV_BOARD_PV_M4900                0x8b
+#define BTTV_BOARD_OSPREY440               0x8c
+#define BTTV_BOARD_ASOUND_SKYEYE          0x8d
+#define BTTV_BOARD_SABRENT_TVFM           0x8e
+#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB     0x8f
+#define BTTV_BOARD_MACHTV_MAGICTV          0x90
+
+/* more card-specific defines */
+#define PT2254_L_CHANNEL 0x10
+#define PT2254_R_CHANNEL 0x08
+#define PT2254_DBS_IN_2 0x400
+#define PT2254_DBS_IN_10 0x20000
+#define WINVIEW_PT2254_CLK  0x40
+#define WINVIEW_PT2254_DATA 0x20
+#define WINVIEW_PT2254_STROBE 0x80
+
+/* digital_mode */
+#define DIGITAL_MODE_VIDEO 1
+#define DIGITAL_MODE_CAMERA 2
+
+struct bttv_core {
+       /* device structs */
+       struct pci_dev       *pci;
+       struct i2c_adapter   i2c_adap;
+       struct list_head     subs;     /* struct bttv_sub_device */
+
+       /* device config */
+       unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
+       unsigned int         type;     /* card type (pointer into tvcards[])  */
+       char                 name[8];  /* dev name */
+};
+
+struct bttv;
+
+
+struct bttv_ir {
+       struct input_dev        *dev;
+       struct ir_input_state   ir;
+       char                    name[32];
+       char                    phys[32];
+
+       /* Usual gpio signalling */
+
+       u32                     mask_keycode;
+       u32                     mask_keydown;
+       u32                     mask_keyup;
+       u32                     polling;
+       u32                     last_gpio;
+       struct work_struct      work;
+       struct timer_list       timer;
+
+       /* RC5 gpio */
+       u32 rc5_gpio;
+       struct timer_list timer_end;    /* timer_end for code completion */
+       struct timer_list timer_keyup;  /* timer_end for key release */
+       u32 last_rc5;                   /* last good rc5 code */
+       u32 last_bit;                   /* last raw bit seen */
+       u32 code;                       /* raw code under construction */
+       struct timeval base_time;       /* time of last seen code */
+       int active;                     /* building raw code */
+};
+
+struct tvcard
+{
+       char *name;
+       unsigned int video_inputs;
+       unsigned int audio_inputs;
+       unsigned int tuner;
+       unsigned int svhs;
+       unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
+       u32 gpiomask;
+       u32 muxsel[16];
+       u32 gpiomux[4];  /* Tuner, Radio, external, internal */
+       u32 gpiomute;    /* GPIO mute setting */
+       u32 gpiomask2;   /* GPIO MUX mask */
+
+       /* i2c audio flags */
+       unsigned int no_msp34xx:1;
+       unsigned int no_tda9875:1;
+       unsigned int no_tda7432:1;
+       unsigned int needs_tvaudio:1;
+       unsigned int msp34xx_alt:1;
+
+       /* flag: video pci function is unused */
+       unsigned int no_video:1;
+       unsigned int has_dvb:1;
+       unsigned int has_remote:1;
+       unsigned int no_gpioirq:1;
+
+       /* other settings */
+       unsigned int pll;
+#define PLL_NONE 0
+#define PLL_28   1
+#define PLL_35   2
+
+       unsigned int tuner_type;
+       unsigned int tuner_addr;
+       unsigned int radio_addr;
+
+       unsigned int has_radio;
+       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+       void (*muxsel_hook)(struct bttv *btv, unsigned int input);
+};
+
+extern struct tvcard bttv_tvcards[];
+
+/* identification / initialization of the card */
+extern void bttv_idcard(struct bttv *btv);
+extern void bttv_init_card1(struct bttv *btv);
+extern void bttv_init_card2(struct bttv *btv);
+
+/* card-specific funtions */
+extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
+extern void bttv_tda9880_setnorm(struct bttv *btv, int norm);
+
+/* extra tweaks for some chipsets */
+extern void bttv_check_chipset(void);
+extern int bttv_handle_chipset(struct bttv *btv);
+
+/* ---------------------------------------------------------- */
+/* exported by bttv-if.c                                      */
+
+/* this obsolete -- please use the sysfs-based
+   interface below for new code */
+
+/* returns card type + card ID (for bt878-based ones)
+   for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
+   returns negative value if error occurred
+*/
+extern int bttv_get_cardinfo(unsigned int card, int *type,
+                            unsigned int *cardid);
+extern struct pci_dev* bttv_get_pcidev(unsigned int card);
+
+/* obsolete, use bttv_get_cardinfo instead */
+extern int bttv_get_id(unsigned int card);
+
+/* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
+   data | (current_GPOE_value & ~mask)
+   returns negative value if error occurred
+*/
+extern int bttv_gpio_enable(unsigned int card,
+                           unsigned long mask, unsigned long data);
+
+/* fills data with GPDATA register contents
+   returns negative value if error occurred
+*/
+extern int bttv_read_gpio(unsigned int card, unsigned long *data);
+
+/* sets GPDATA register to new value:
+  (data & mask) | (current_GPDATA_value & ~mask)
+  returns negative value if error occurred
+*/
+extern int bttv_write_gpio(unsigned int card,
+                          unsigned long mask, unsigned long data);
+
+/* returns pointer to task queue which can be used as parameter to
+   interruptible_sleep_on
+   in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
+   (wake_up_interruptible) and following call to the function bttv_read_gpio
+   should return new value of GPDATA,
+   returns NULL value if error occurred or queue is not available
+   WARNING: because there is no buffer for GPIO data, one MUST
+   process data ASAP
+*/
+extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
+
+/* call i2c clients
+*/
+extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
+
+
+
+/* ---------------------------------------------------------- */
+/* sysfs/driver-moded based gpio access interface             */
+
+
+struct bttv_sub_device {
+       struct device    dev;
+       struct bttv_core *core;
+       struct list_head list;
+};
+#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev)
+
+struct bttv_sub_driver {
+       struct device_driver   drv;
+       char                   wanted[BUS_ID_SIZE];
+       int                    (*probe)(struct bttv_sub_device *sub);
+       void                   (*remove)(struct bttv_sub_device *sub);
+       void                   (*gpio_irq)(struct bttv_sub_device *sub);
+};
+#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
+
+int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted);
+int bttv_sub_unregister(struct bttv_sub_driver *drv);
+
+/* gpio access functions */
+void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits);
+u32 bttv_gpio_read(struct bttv_core *core);
+void bttv_gpio_write(struct bttv_core *core, u32 value);
+void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
+
+#define gpio_inout(mask,bits)  bttv_gpio_inout(&btv->c, mask, bits)
+#define gpio_read()            bttv_gpio_read(&btv->c)
+#define gpio_write(value)      bttv_gpio_write(&btv->c, value)
+#define gpio_bits(mask,bits)   bttv_gpio_bits(&btv->c, mask, bits)
+
+
+/* ---------------------------------------------------------- */
+/* i2c                                                        */
+
+extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
+extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
+extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+                        unsigned char b2, int both);
+extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
+
+extern int bttv_input_init(struct bttv *dev);
+extern void bttv_input_fini(struct bttv *dev);
+extern void bttv_input_irq(struct bttv *dev);
+
+#endif /* _BTTV_H_ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
new file mode 100644 (file)
index 0000000..ee989d2
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+
+    bttv - Bt848 frame grabber driver
+
+    bttv's *private* header file  --  nobody other than bttv itself
+    should ever include this file.
+
+    (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BTTVP_H_
+#define _BTTVP_H_
+
+#include <linux/version.h>
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/videodev.h>
+#include <linux/pci.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+#include <linux/device.h>
+#include <media/video-buf.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/ir-common.h>
+
+
+#include "bt848.h"
+#include "bttv.h"
+#include "btcx-risc.h"
+
+#ifdef __KERNEL__
+
+#define FORMAT_FLAGS_DITHER       0x01
+#define FORMAT_FLAGS_PACKED       0x02
+#define FORMAT_FLAGS_PLANAR       0x04
+#define FORMAT_FLAGS_RAW          0x08
+#define FORMAT_FLAGS_CrCb         0x10
+
+#define RISC_SLOT_O_VBI        4
+#define RISC_SLOT_O_FIELD      6
+#define RISC_SLOT_E_VBI       10
+#define RISC_SLOT_E_FIELD     12
+#define RISC_SLOT_LOOP        14
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+#define RAW_LINES            640
+#define RAW_BPL             1024
+
+#define UNSET (-1U)
+
+#define clamp(x, low, high) min (max (low, x), high)
+
+/* ---------------------------------------------------------- */
+
+struct bttv_tvnorm {
+       int   v4l2_id;
+       char  *name;
+       u32   Fsc;
+       u16   swidth, sheight; /* scaled standard width, height */
+       u16   totalwidth;
+       u8    adelay, bdelay, iform;
+       u32   scaledtwidth;
+       u16   hdelayx1, hactivex1;
+       u16   vdelay;
+       u8    vbipack;
+       u16   vtotal;
+       int   sram;
+       /* ITU-R frame line number of the first VBI line we can
+          capture, of the first and second field. */
+       u16   vbistart[2];
+};
+extern const struct bttv_tvnorm bttv_tvnorms[];
+
+struct bttv_format {
+       char *name;
+       int  palette;         /* video4linux 1      */
+       int  fourcc;          /* video4linux 2      */
+       int  btformat;        /* BT848_COLOR_FMT_*  */
+       int  btswap;          /* BT848_COLOR_CTL_*  */
+       int  depth;           /* bit/pixel          */
+       int  flags;
+       int  hshift,vshift;   /* for planar modes   */
+};
+
+/* ---------------------------------------------------------- */
+
+struct bttv_geometry {
+       u8  vtc,crop,comb;
+       u16 width,hscale,hdelay;
+       u16 sheight,vscale,vdelay,vtotal;
+};
+
+struct bttv_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer     vb;
+
+       /* bttv specific */
+       const struct bttv_format   *fmt;
+       int                        tvnorm;
+       int                        btformat;
+       int                        btswap;
+       struct bttv_geometry       geo;
+       struct btcx_riscmem        top;
+       struct btcx_riscmem        bottom;
+};
+
+struct bttv_buffer_set {
+       struct bttv_buffer     *top;       /* top field buffer    */
+       struct bttv_buffer     *bottom;    /* bottom field buffer */
+       unsigned int           top_irq;
+       unsigned int           frame_irq;
+};
+
+struct bttv_overlay {
+       int                    tvnorm;
+       struct v4l2_rect       w;
+       enum v4l2_field        field;
+       struct v4l2_clip       *clips;
+       int                    nclips;
+       int                    setup_ok;
+};
+
+struct bttv_fh {
+       struct bttv              *btv;
+       int resources;
+#ifdef VIDIOC_G_PRIORITY
+       enum v4l2_priority       prio;
+#endif
+       enum v4l2_buf_type       type;
+
+       /* video capture */
+       struct videobuf_queue    cap;
+       const struct bttv_format *fmt;
+       int                      width;
+       int                      height;
+
+       /* current settings */
+       const struct bttv_format *ovfmt;
+       struct bttv_overlay      ov;
+
+       /* video overlay */
+       struct videobuf_queue    vbi;
+       int                      lines;
+};
+
+/* ---------------------------------------------------------- */
+/* bttv-risc.c                                                */
+
+/* risc code generators - capture */
+int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
+                    struct scatterlist *sglist,
+                    unsigned int offset, unsigned int bpl,
+                    unsigned int pitch, unsigned int lines);
+
+/* control dma register + risc main loop */
+void bttv_set_dma(struct bttv *btv, int override);
+int bttv_risc_init_main(struct bttv *btv);
+int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
+                  int irqflags);
+
+/* capture buffer handling */
+int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
+int bttv_buffer_activate_video(struct bttv *btv,
+                              struct bttv_buffer_set *set);
+int bttv_buffer_activate_vbi(struct bttv *btv,
+                            struct bttv_buffer *vbi);
+void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv,
+                  struct bttv_buffer *buf);
+
+/* overlay handling */
+int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
+                     const struct bttv_format *fmt,
+                     struct bttv_buffer *buf);
+
+
+/* ---------------------------------------------------------- */
+/* bttv-vbi.c                                                 */
+
+void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
+void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
+void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
+
+extern struct videobuf_queue_ops bttv_vbi_qops;
+
+/* ---------------------------------------------------------- */
+/* bttv-gpio.c */
+
+
+extern struct bus_type bttv_sub_bus_type;
+int bttv_sub_add_device(struct bttv_core *core, char *name);
+int bttv_sub_del_devices(struct bttv_core *core);
+void bttv_gpio_irq(struct bttv_core *core);
+
+
+/* ---------------------------------------------------------- */
+/* bttv-driver.c                                              */
+
+/* insmod options */
+extern unsigned int bttv_verbose;
+extern unsigned int bttv_debug;
+extern unsigned int bttv_gpio;
+extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
+extern int init_bttv_i2c(struct bttv *btv);
+extern int fini_bttv_i2c(struct bttv *btv);
+
+#define bttv_printk if (bttv_verbose) printk
+#define dprintk  if (bttv_debug >= 1) printk
+#define d2printk if (bttv_debug >= 2) printk
+
+#define BTTV_MAX_FBUF   0x208000
+#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
+#define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
+#define BTTV_FREE_IDLE  (HZ)   /* one second */
+
+
+struct bttv_pll_info {
+       unsigned int pll_ifreq;    /* PLL input frequency        */
+       unsigned int pll_ofreq;    /* PLL output frequency       */
+       unsigned int pll_crystal;  /* Crystal used for input     */
+       unsigned int pll_current;  /* Currently programmed ofreq */
+};
+
+/* for gpio-connected remote control */
+struct bttv_input {
+       struct input_dev      *dev;
+       struct ir_input_state ir;
+       char                  name[32];
+       char                  phys[32];
+       u32                   mask_keycode;
+       u32                   mask_keydown;
+};
+
+struct bttv_suspend_state {
+       u32  gpio_enable;
+       u32  gpio_data;
+       int  disabled;
+       int  loop_irq;
+       struct bttv_buffer_set video;
+       struct bttv_buffer     *vbi;
+};
+
+struct bttv {
+       struct bttv_core c;
+
+       /* pci device config */
+       unsigned short id;
+       unsigned char revision;
+       unsigned char __iomem *bt848_mmio;   /* pointer to mmio */
+
+       /* card configuration info */
+       unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
+       unsigned int tuner_type;  /* tuner chip type */
+       unsigned int tda9887_conf;
+       unsigned int svhs;
+       struct bttv_pll_info pll;
+       int triton1;
+       int gpioirq;
+       int (*custom_irq)(struct bttv *btv);
+
+       int use_i2c_hw;
+
+       /* old gpio interface */
+       wait_queue_head_t gpioq;
+       int shutdown;
+       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+
+       /* new gpio interface */
+       spinlock_t gpio_lock;
+
+       /* i2c layer */
+       struct i2c_algo_bit_data   i2c_algo;
+       struct i2c_client          i2c_client;
+       int                        i2c_state, i2c_rc;
+       int                        i2c_done;
+       wait_queue_head_t          i2c_queue;
+       struct i2c_client         *i2c_msp34xx_client;
+       struct i2c_client         *i2c_tvaudio_client;
+
+       /* video4linux (1) */
+       struct video_device *video_dev;
+       struct video_device *radio_dev;
+       struct video_device *vbi_dev;
+
+       /* infrared remote */
+       int has_remote;
+       struct bttv_ir *remote;
+
+       /* locking */
+       spinlock_t s_lock;
+       struct mutex lock;
+       int resources;
+       struct mutex reslock;
+#ifdef VIDIOC_G_PRIORITY
+       struct v4l2_prio_state prio;
+#endif
+
+       /* video state */
+       unsigned int input;
+       unsigned int audio;
+       unsigned int mute;
+       unsigned long freq;
+       int tvnorm,hue,contrast,bright,saturation;
+       struct v4l2_framebuffer fbuf;
+       unsigned int field_count;
+
+       /* various options */
+       int opt_combfilter;
+       int opt_lumafilter;
+       int opt_automute;
+       int opt_chroma_agc;
+       int opt_adc_crush;
+       int opt_vcr_hack;
+       int opt_whitecrush_upper;
+       int opt_whitecrush_lower;
+       int opt_uv_ratio;
+       int opt_full_luma_range;
+       int opt_coring;
+
+       /* radio data/state */
+       int has_radio;
+       int radio_user;
+
+       /* miro/pinnacle + Aimslab VHX
+          philips matchbox (tea5757 radio tuner) support */
+       int has_matchbox;
+       int mbox_we;
+       int mbox_data;
+       int mbox_clk;
+       int mbox_most;
+       int mbox_mask;
+
+       /* ISA stuff (Terratec Active Radio Upgrade) */
+       int mbox_ior;
+       int mbox_iow;
+       int mbox_csel;
+
+       /* risc memory management data
+          - must aquire s_lock before changing these
+          - only the irq handler is supported to touch top + bottom + vcurr */
+       struct btcx_riscmem     main;
+       struct bttv_buffer      *screen;    /* overlay             */
+       struct list_head        capture;    /* video capture queue */
+       struct list_head        vcapture;   /* vbi capture queue   */
+       struct bttv_buffer_set  curr;       /* active buffers      */
+       struct bttv_buffer      *cvbi;      /* active vbi buffer   */
+       int                     loop_irq;
+       int                     new_input;
+
+       unsigned long cap_ctl;
+       unsigned long dma_on;
+       struct timer_list timeout;
+       struct bttv_suspend_state state;
+
+       /* stats */
+       unsigned int errors;
+       unsigned int framedrop;
+       unsigned int irq_total;
+       unsigned int irq_me;
+
+       unsigned int users;
+       struct bttv_fh init;
+};
+
+/* our devices */
+#define BTTV_MAX 16
+extern unsigned int bttv_num;
+extern struct bttv bttvs[BTTV_MAX];
+
+/* private ioctls */
+#define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
+
+#endif
+
+#define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
+#define btread(adr)         readl(btv->bt848_mmio+(adr))
+
+#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+#endif /* _BTTVP_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
deleted file mode 100644 (file)
index abfa6ad..0000000
+++ /dev/null
@@ -1,5011 +0,0 @@
-/*
-
-    bttv-cards.c
-
-    this file has configuration informations - card-specific stuff
-    like the big tvcards array for the most part
-
-    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                          & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/firmware.h>
-
-#include <asm/io.h>
-
-#include "bttvp.h"
-#include <media/v4l2-common.h>
-
-/* fwd decl */
-static void boot_msp34xx(struct bttv *btv, int pin);
-static void boot_bt832(struct bttv *btv);
-static void hauppauge_eeprom(struct bttv *btv);
-static void avermedia_eeprom(struct bttv *btv);
-static void osprey_eeprom(struct bttv *btv);
-static void modtec_eeprom(struct bttv *btv);
-static void init_PXC200(struct bttv *btv);
-static void init_RTV24(struct bttv *btv);
-
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
-static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
-static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
-                                   int set);
-static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
-                                     int set);
-static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
-static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
-static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
-static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
-static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
-static void rv605_muxsel(struct bttv *btv, unsigned int input);
-static void eagle_muxsel(struct bttv *btv, unsigned int input);
-static void xguard_muxsel(struct bttv *btv, unsigned int input);
-static void ivc120_muxsel(struct bttv *btv, unsigned int input);
-static void gvc1100_muxsel(struct bttv *btv, unsigned int input);
-
-static void PXC200_muxsel(struct bttv *btv, unsigned int input);
-
-static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input);
-static void picolo_tetra_init(struct bttv *btv);
-
-static void tibetCS16_muxsel(struct bttv *btv, unsigned int input);
-static void tibetCS16_init(struct bttv *btv);
-
-static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input);
-static void kodicom4400r_init(struct bttv *btv);
-
-static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
-static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
-
-static int terratec_active_radio_upgrade(struct bttv *btv);
-static int tea5757_read(struct bttv *btv);
-static int tea5757_write(struct bttv *btv, int value);
-static void identify_by_eeprom(struct bttv *btv,
-                              unsigned char eeprom_data[256]);
-static int __devinit pvr_boot(struct bttv *btv);
-
-/* config variables */
-static unsigned int triton1;
-static unsigned int vsfx;
-static unsigned int latency = UNSET;
-int no_overlay=-1;
-
-static unsigned int card[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
-static unsigned int pll[BTTV_MAX]    = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
-static unsigned int tuner[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
-static unsigned int svhs[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
-static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET };
-static struct bttv  *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL };
-#ifdef MODULE
-static unsigned int autoload = 1;
-#else
-static unsigned int autoload;
-#endif
-static unsigned int gpiomask = UNSET;
-static unsigned int audioall = UNSET;
-static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
-
-/* insmod options */
-module_param(triton1,    int, 0444);
-module_param(vsfx,       int, 0444);
-module_param(no_overlay, int, 0444);
-module_param(latency,    int, 0444);
-module_param(gpiomask,   int, 0444);
-module_param(audioall,   int, 0444);
-module_param(autoload,   int, 0444);
-
-module_param_array(card,     int, NULL, 0444);
-module_param_array(pll,      int, NULL, 0444);
-module_param_array(tuner,    int, NULL, 0444);
-module_param_array(svhs,     int, NULL, 0444);
-module_param_array(remote,   int, NULL, 0444);
-module_param_array(audiomux, int, NULL, 0444);
-
-MODULE_PARM_DESC(triton1,"set ETBF pci config bit "
-                "[enable bug compatibility for triton1 + others]");
-MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
-                "[yet another chipset flaw workaround]");
-MODULE_PARM_DESC(latency,"pci latency timer");
-MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
-MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
-MODULE_PARM_DESC(tuner,"specify installed tuner type");
-MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
-MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
-               " [some VIA/SIS chipsets are known to have problem with overlay]");
-
-/* ----------------------------------------------------------------------- */
-/* list of card IDs for bt878+ cards                                       */
-
-static struct CARD {
-       unsigned id;
-       int cardnr;
-       char *name;
-} cards[] __devinitdata = {
-       { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV" },
-       { 0x39000070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV-D" },
-       { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
-       { 0xff000070, BTTV_BOARD_OSPREY1x0,     "Osprey-100" },
-       { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
-       { 0xff020070, BTTV_BOARD_OSPREY500,     "Osprey-500" },
-       { 0xff030070, BTTV_BOARD_OSPREY2000,    "Osprey-2000" },
-       { 0xff040070, BTTV_BOARD_OSPREY540,     "Osprey-540" },
-       { 0xff070070, BTTV_BOARD_OSPREY440,     "Osprey-440" },
-
-       { 0x00011002, BTTV_BOARD_ATI_TVWONDER,  "ATI TV Wonder" },
-       { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
-
-       { 0x6606107d, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0x6607107d, BTTV_BOARD_WINFASTVC100,  "Leadtek WinFast VC 100" },
-       { 0x6609107d, BTTV_BOARD_WINFAST2000,   "Leadtek TV 2000 XP" },
-       { 0x263610b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
-       { 0x264510b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
-       { 0x402010fc, BTTV_BOARD_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
-       { 0x405010fc, BTTV_BOARD_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
-       { 0x407010fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
-       { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
-
-       { 0x001211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
-       /* some cards ship with byteswapped IDs ... */
-       { 0x1200bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
-       { 0xff00bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
-       /* this seems to happen as well ... */
-       { 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
-
-       { 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-       { 0x3060121a, BTTV_BOARD_STB2,    "3Dfx VoodooTV 100/ STB OEM" },
-
-       { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
-       { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
-       { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
-       { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
-       { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
-       { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
-       { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
-
-       { 0x00011461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
-       { 0x00021461, BTTV_BOARD_AVERMEDIA98,   "AVermedia TVCapture 98" },
-       { 0x00031461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
-       { 0x00041461, BTTV_BOARD_AVERMEDIA98,   "AVerMedia TVCapture 98" },
-       { 0x03001461, BTTV_BOARD_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
-
-       { 0x1117153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
-       { 0x1118153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
-       { 0x1119153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
-       { 0x111a153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
-
-       { 0x1123153b, BTTV_BOARD_TERRATVRADIO,  "Terratec TV Radio+" },
-       { 0x1127153b, BTTV_BOARD_TERRATV,       "Terratec TV+ (V1.05)"    },
-       /* clashes with FlyVideo
-        *{ 0x18521852, BTTV_BOARD_TERRATV,     "Terratec TV+ (V1.10)"    }, */
-       { 0x1134153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (LR102)" },
-       { 0x1135153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
-       { 0x5018153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue" },       /* ?? */
-       { 0xff3b153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
-
-       { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-       { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-       { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-       { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-       { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-
-       { 0x1430aa00, BTTV_BOARD_PV143,         "Provideo PV143A" },
-       { 0x1431aa00, BTTV_BOARD_PV143,         "Provideo PV143B" },
-       { 0x1432aa00, BTTV_BOARD_PV143,         "Provideo PV143C" },
-       { 0x1433aa00, BTTV_BOARD_PV143,         "Provideo PV143D" },
-       { 0x1433aa03, BTTV_BOARD_PV143,         "Security Eyes" },
-
-       { 0x1460aa00, BTTV_BOARD_PV150,         "Provideo PV150A-1" },
-       { 0x1461aa01, BTTV_BOARD_PV150,         "Provideo PV150A-2" },
-       { 0x1462aa02, BTTV_BOARD_PV150,         "Provideo PV150A-3" },
-       { 0x1463aa03, BTTV_BOARD_PV150,         "Provideo PV150A-4" },
-
-       { 0x1464aa04, BTTV_BOARD_PV150,         "Provideo PV150B-1" },
-       { 0x1465aa05, BTTV_BOARD_PV150,         "Provideo PV150B-2" },
-       { 0x1466aa06, BTTV_BOARD_PV150,         "Provideo PV150B-3" },
-       { 0x1467aa07, BTTV_BOARD_PV150,         "Provideo PV150B-4" },
-
-       { 0xa132ff00, BTTV_BOARD_IVC100,        "IVC-100"  },
-       { 0xa1550000, BTTV_BOARD_IVC200,        "IVC-200"  },
-       { 0xa1550001, BTTV_BOARD_IVC200,        "IVC-200"  },
-       { 0xa1550002, BTTV_BOARD_IVC200,        "IVC-200"  },
-       { 0xa1550003, BTTV_BOARD_IVC200,        "IVC-200"  },
-       { 0xa1550100, BTTV_BOARD_IVC200,        "IVC-200G" },
-       { 0xa1550101, BTTV_BOARD_IVC200,        "IVC-200G" },
-       { 0xa1550102, BTTV_BOARD_IVC200,        "IVC-200G" },
-       { 0xa1550103, BTTV_BOARD_IVC200,        "IVC-200G" },
-       { 0xa182ff00, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff01, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff02, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff03, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff04, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff05, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff06, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff07, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff08, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff09, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff0a, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff0b, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff0c, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff0d, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff0e, BTTV_BOARD_IVC120,        "IVC-120G" },
-       { 0xa182ff0f, BTTV_BOARD_IVC120,        "IVC-120G" },
-
-       { 0x41424344, BTTV_BOARD_GRANDTEC,      "GrandTec Multi Capture" },
-       { 0x01020304, BTTV_BOARD_XGUARD,        "Grandtec Grand X-Guard" },
-
-       { 0x18501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
-       { 0xa0501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
-       { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
-       { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
-       { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
-       { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
-
-       { 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
-       { 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
-
-       { 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
-       { 0x217d6606, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0xfff6f6ff, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
-       { 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
-       { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
-       { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
-       { 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
-       { 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
-
-       { 0x40111554, BTTV_BOARD_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
-       { 0x17de0a01, BTTV_BOARD_KWORLD,        "Mecer TV/FM/Video Tuner" },
-
-       { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
-       { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
-       { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
-       { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
-
-       { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
-
-       /* likely broken, vendor id doesn't match the other magic views ...
-        * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
-
-       /* Duplicate PCI ID, reconfigure for this board during the eeprom read.
-       * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
-
-       /* DVB cards (using pci function .1 for mpeg data xfer) */
-       { 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
-       { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
-       { 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
-       { 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
-       { 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
-       { 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
-       { 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
-       { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
-       { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
-       { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
-
-       { 0, -1, NULL }
-};
-
-/* ----------------------------------------------------------------------- */
-/* array with description for bt848 / bt878 tv/grabber cards               */
-
-struct tvcard bttv_tvcards[] = {
-       /* ---- card 0x00 ---------------------------------- */
-       [BTTV_BOARD_UNKNOWN] = {
-               .name           = " *** UNKNOWN/GENERIC *** ",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MIRO] = {
-               .name           = "MIRO PCTV",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 2, 0, 0, 0, 10 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_HAUPPAUGE] = {
-               .name           = "Hauppauge (bt848)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 1, 2, 3, 4 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_STB] = {
-               .name           = "STB, Gateway P/N 6000699 (bt848)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 4, 0, 2, 3, 1 },
-               .no_msp34xx     = 1,
-               .needs_tvaudio  = 1,
-               .tuner_type     = TUNER_PHILIPS_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .has_radio      = 1,
-       },
-
-       /* ---- card 0x04 ---------------------------------- */
-       [BTTV_BOARD_INTEL] = {
-               .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 2,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .tuner_type     = 4,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_DIAMOND] = {
-               .name           = "Diamond DTV2000",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 0, 1, 0, 1, 3 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_AVERMEDIA] = {
-               .name           = "AVerMedia TVPhone",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 3,
-               .muxsel         = { 2, 3, 1, 1 },
-               .gpiomask       = 0x0f,
-               .audiomux       = { 0x0c, 0x04, 0x08, 0x04, 0 },
-               /*                0x04 for some cards ?? */
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = avermedia_tvphone_audio,
-               .has_remote     = 1,
-       },
-       [BTTV_BOARD_MATRIX_VISION] = {
-               .name           = "MATRIX-Vision MV-Delta",
-               .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 3,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x08 ---------------------------------- */
-       [BTTV_BOARD_FLYVIDEO] = {
-               .name           = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xc00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0xc00, 0x800, 0x400, 0xc00, 0 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_TURBOTV] = {
-               .name           = "IMS/IXmicro TurboTV",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 1, 1, 2, 3, 0 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TEMIC_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_HAUPPAUGE878] = {
-               .name           = "Hauppauge (bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x0f, /* old: 7 */
-               .muxsel         = { 2, 0, 1, 1 },
-               .audiomux       = { 0, 1, 2, 3, 4 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MIROPRO] = {
-               .name           = "MIRO PCTV pro",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x3014f,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x20001,0x10001, 0, 0,10 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x0c ---------------------------------- */
-       [BTTV_BOARD_ADSTECH_TV] = {
-               .name           = "ADS Technologies Channel Surfer TV (bt848)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 13, 14, 11, 7, 0, 0 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_AVERMEDIA98] = {
-               .name           = "AVerMedia TVCapture 98",
-               .video_inputs   = 3,
-               .audio_inputs   = 4,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 13, 14, 11, 7, 0, 0 },
-               .needs_tvaudio  = 1,
-               .msp34xx_alt    = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = avermedia_tv_stereo_audio,
-               .no_gpioirq     = 1,
-       },
-       [BTTV_BOARD_VHX] = {
-               .name           = "Aimslab Video Highway Xtreme (VHX)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 2, 1, 3, 4 }, /* old: {0, 1, 2, 3, 4} */
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_ZOLTRIX] = {
-               .name           = "Zoltrix TV-Max",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0 , 0, 1 , 0, 10 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x10 ---------------------------------- */
-       [BTTV_BOARD_PIXVIEWPLAYTV] = {
-               .name           = "Prolink Pixelview PlayTV (bt878)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x01fe00,
-               .muxsel         = { 2, 3, 1, 1 },
-       #if 0
-               /* old */
-               .audiomux       = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
-       #else
-               /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
-               .audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-       #endif
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-       },
-       [BTTV_BOARD_WINVIEW_601] = {
-               .name           = "Leadtek WinView 601",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x8300f8,
-               .muxsel         = { 2, 3, 1, 1,0 },
-               .audiomux       = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = winview_audio,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_AVEC_INTERCAP] = {
-               .name           = "AVEC Intercapture",
-               .video_inputs   = 3,
-               .audio_inputs   = 2,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 1, 0, 0, 0, 0 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_LIFE_FLYKIT] = {
-               .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0x8dff00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0 },
-               .no_msp34xx     = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x14 ---------------------------------- */
-       [BTTV_BOARD_CEI_RAFFLES] = {
-               .name           = "CEI Raffles Card",
-               .video_inputs   = 3,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1 },
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_CONFERENCETV] = {
-               .name           = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
-               .video_inputs   = 4,
-               .audio_inputs   = 2,  /* tuner, line in */
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800 },
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL_I,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_PHOEBE_TVMAS] = {
-               .name           = "Askey CPH050/ Phoebe Tv Master + FM",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xc00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 1, 0x800, 0x400, 0xc00, 0 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MODTEC_205] = {
-               .name           = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, -1 },
-               .digital_mode   = DIGITAL_MODE_CAMERA,
-               .audiomux       = { 0, 0, 0, 0, 0 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x18 ---------------------------------- */
-       [BTTV_BOARD_MAGICTVIEW061] = {
-               .name           = "Askey CPH05X/06X (bt878) [many vendors]",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xe00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = {0x400, 0x400, 0x400, 0x400, 0xc00 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-       },
-       [BTTV_BOARD_VOBIS_BOOSTAR] = {
-               .name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1f0fff,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000 },
-               .needs_tvaudio  = 0,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = terratv_audio,
-       },
-       [BTTV_BOARD_HAUPPAUG_WCAM] = {
-               .name           = "Hauppauge WinCam newer (bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 3,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 0, 1, 1 },
-               .audiomux       = { 0, 1, 2, 3, 4 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MAXI] = {
-               .name           = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
-               .video_inputs   = 4,
-               .audio_inputs   = 2,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800 },
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_SECAM,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x1c ---------------------------------- */
-       [BTTV_BOARD_TERRATV] = {
-               .name           = "Terratec TerraTV+ Version 1.1 (bt878)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1f0fff,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000 },
-               .needs_tvaudio  = 0,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = terratv_audio,
-               /* GPIO wiring:
-               External 20 pin connector (for Active Radio Upgrade board)
-               gpio00: i2c-sda
-               gpio01: i2c-scl
-               gpio02: om5610-data
-               gpio03: om5610-clk
-               gpio04: om5610-wre
-               gpio05: om5610-stereo
-               gpio06: rds6588-davn
-               gpio07: Pin 7 n.c.
-               gpio08: nIOW
-               gpio09+10: nIOR, nSEL ?? (bt878)
-                       gpio09: nIOR (bt848)
-                       gpio10: nSEL (bt848)
-               Sound Routing:
-               gpio16: u2-A0 (1st 4052bt)
-               gpio17: u2-A1
-               gpio18: u2-nEN
-               gpio19: u4-A0 (2nd 4052)
-               gpio20: u4-A1
-                       u4-nEN - GND
-               Btspy:
-                       00000 : Cdrom (internal audio input)
-                       10000 : ext. Video audio input
-                       20000 : TV Mono
-                       a0000 : TV Mono/2
-               1a0000 : TV Stereo
-                       30000 : Radio
-                       40000 : Mute
-       */
-
-       },
-       [BTTV_BOARD_PXC200] = {
-               /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
-               .name           = "Imagenation PXC200",
-               .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 1, /* was: 4 */
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0},
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .muxsel_hook    = PXC200_muxsel,
-
-       },
-       [BTTV_BOARD_FLYVIDEO_98] = {
-               .name           = "Lifeview FlyVideo 98 LR50",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1800,  /* 0x8dfe00 */
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_IPROTV] = {
-               .name           = "Formac iProTV, Formac ProTV I (bt848)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 3,
-               .gpiomask       = 1,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 1, 0, 0, 0, 0 },
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x20 ---------------------------------- */
-       [BTTV_BOARD_INTEL_C_S_PCI] = {
-               .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 2,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .tuner_type     = 4,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_TERRATVALUE] = {
-               .name           = "Terratec TerraTValue Version Bt878",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xffff00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x500, 0, 0x300, 0x900, 0x900 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_WINFAST2000] = {
-               .name           = "Leadtek WinFast 2000/ WinFast 2000 XP",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
-       #if 0
-               .gpiomask       = 0xc33000,
-               .audiomux       = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
-       #else
-               /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
-               .gpiomask       = 0xb33000,
-               .audiomux       = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
-       #endif
-               /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
-                       gpio23 -- hef4052:nEnable (0x800000)
-                       gpio12 -- hef4052:A1
-                       gpio13 -- hef4052:A0
-               0x0000: external audio
-               0x1000: FM
-               0x2000: TV
-               0x3000: n.c.
-               Note: There exists another variant "Winfast 2000" with tv stereo !?
-               Note: eeprom only contains FF and pci subsystem id 107d:6606
-               */
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .has_radio      = 1,
-               .tuner_type     = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = winfast2000_audio,
-               .has_remote     = 1,
-       },
-       [BTTV_BOARD_CHRONOS_VS2] = {
-               .name           = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
-               .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x24 ---------------------------------- */
-       [BTTV_BOARD_TYPHOON_TVIEW] = {
-               .name           = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
-               .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_PXELVWPLTVPRO] = {
-               .name           = "Prolink PixelView PlayTV pro",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xff,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MAGICTVIEW063] = {
-               .name           = "Askey CPH06X TView99",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x551e00,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-       },
-       [BTTV_BOARD_PINNACLE] = {
-               .name           = "Pinnacle PCTV Studio/Rave",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x03000F,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 2, 0xd0001, 0, 0, 1 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x28 ---------------------------------- */
-       [BTTV_BOARD_STB2] = {
-               .name           = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 4, 0, 2, 3, 1 },
-               .no_msp34xx     = 1,
-               .needs_tvaudio  = 1,
-               .tuner_type     = TUNER_PHILIPS_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_AVPHONE98] = {
-               .name           = "AVerMedia TVPhone 98",
-               .video_inputs   = 3,
-               .audio_inputs   = 4,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 13, 4, 11, 7, 0, 0 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-               .audio_hook     = avermedia_tvphone_audio,
-       },
-       [BTTV_BOARD_PV951] = {
-               .name           = "ProVideo PV951", /* pic16c54 */
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 1},
-               .audiomux       = { 0, 0, 0, 0, 0},
-               .needs_tvaudio  = 1,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_ONAIR_TV] = {
-               .name           = "Little OnAir TV",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xe00b,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc },
-               .no_msp34xx     = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x2c ---------------------------------- */
-       [BTTV_BOARD_SIGMA_TVII_FM] = {
-               .name           = "Sigma TVII-FM",
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 1, 1, 0, 2, 3 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_NONE,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MATRIX_VISION2] = {
-               .name           = "MATRIX-Vision MV-Delta 2",
-               .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 3,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0 },
-               .audiomux       = { 0 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_ZOLTRIX_GENIE] = {
-               .name           = "Zoltrix Genie TV/FM",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xbcf03f,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 21,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_TERRATVRADIO] = {
-               .name           = "Terratec TV/Radio+",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x70000,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
-               .needs_tvaudio  = 1,
-               .no_msp34xx     = 1,
-               .pll            = PLL_35,
-               .tuner_type     = 1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-       },
-
-       /* ---- card 0x30 ---------------------------------- */
-       [BTTV_BOARD_DYNALINK] = {
-               .name           = "Askey CPH03x/ Dynalink Magic TView",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = {2,0,0,0,1 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_GVBCTV3PCI] = {
-               .name           = "IODATA GV-BCTV3/PCI",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x010f00,
-               .muxsel         = {2, 3, 0, 0 },
-               .audiomux       = {0x10000, 0, 0x10000, 0, 0, 0 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_ALPS_TSHC6_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = gvbctv3pci_audio,
-       },
-       [BTTV_BOARD_PXELVWPLTVPAK] = {
-               .name           = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
-               .video_inputs   = 5,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 3,
-               .gpiomask       = 0xAA0000,
-               .muxsel         = { 2,3,1,1,-1 },
-               .digital_mode   = DIGITAL_MODE_CAMERA,
-               .audiomux       = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL_I,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-               /* GPIO wiring: (different from Rev.4C !)
-                       GPIO17: U4.A0 (first hef4052bt)
-                       GPIO19: U4.A1
-                       GPIO20: U5.A1 (second hef4052bt)
-                       GPIO21: U4.nEN
-                       GPIO22: BT832 Reset Line
-                       GPIO23: A5,A0, U5,nEN
-               Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
-               */
-       },
-       [BTTV_BOARD_EAGLE] = {
-               .name           = "Eagle Wireless Capricorn2 (bt878A)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 0, 1, 1 },
-               .audiomux       = { 0, 1, 2, 3, 4 },
-               .pll            = PLL_28,
-               .tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x34 ---------------------------------- */
-       [BTTV_BOARD_PINNACLEPRO] = {
-               /* David Härdeman <david@2gen.com> */
-               .name           = "Pinnacle PCTV Studio Pro",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 3,
-               .gpiomask       = 0x03000F,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 1, 0xd0001, 0, 0, 10 },
-                               /* sound path (5 sources):
-                               MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
-                                       0= ext. Audio IN
-                                       1= from MUX2
-                                       2= Mono TV sound from Tuner
-                                       3= not connected
-                               MUX2 (mask 0x30000):
-                                       0,2,3= from MSP34xx
-                                       1= FM stereo Radio from Tuner */
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_TVIEW_RDS_FM] = {
-               /* Claas Langbehn <claas@bigfoot.com>,
-               Sven Grothklags <sven@upb.de> */
-               .name           = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
-               .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1c,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0, 0x10, 8, 4 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_LIFETEC_9415] = {
-               /* Tim Röstermundt <rosterm@uni-muenster.de>
-               in de.comp.os.unix.linux.hardware:
-                       options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
-                       audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
-                       options tuner type=5 */
-               .name           = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x18e0,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
-                       /* For cards with tda9820/tda9821:
-                               0x0000: Tuner normal stereo
-                               0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
-                               0x0880: Tuner A2 stereo */
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_BESTBUY_EASYTV] = {
-               /* Miguel Angel Alvarez <maacruz@navegalia.com>
-               old Easy TV BT848 version (model CPH031) */
-               .name           = "Askey CPH031/ BESTBUY Easy TV",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xF,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 2, 0, 0, 0, 10 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TEMIC_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x38 ---------------------------------- */
-       [BTTV_BOARD_FLYVIDEO_98FM] = {
-               /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-               .name           = "Lifeview FlyVideo 98FM LR50",
-               .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1800,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-               .pll            = PLL_28,
-               .tuner_type     = 5,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-               /* This is the ultimate cheapo capture card
-               * just a BT848A on a small PCB!
-               * Steve Hosgood <steve@equiinet.com> */
-       [BTTV_BOARD_GRANDTEC] = {
-               .name           = "GrandTec 'Grand Video Capture' (Bt848)",
-               .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 1,
-               .gpiomask       = 0,
-               .muxsel         = { 3, 1 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .pll            = PLL_35,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_ASKEY_CPH060] = {
-               /* Daniel Herrington <daniel.herrington@home.com> */
-               .name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xe00,
-               .muxsel         = { 2, 3, 1, 1},
-               .audiomux       = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_ASKEY_CPH03X] = {
-               /* Matti Mottus <mottus@physic.ut.ee> */
-               .name           = "Askey CPH03x TV Capturer",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x03000F,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 2, 0, 0, 0, 1 },
-               .pll            = PLL_28,
-               .tuner_type     = 0,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x3c ---------------------------------- */
-       [BTTV_BOARD_MM100PCTV] = {
-               /* Philip Blundell <philb@gnu.org> */
-               .name           = "Modular Technology MM100PCTV",
-               .video_inputs   = 2,
-               .audio_inputs   = 2,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 11,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 2, 0, 0, 1, 8 },
-               .pll            = PLL_35,
-               .tuner_type     = TUNER_TEMIC_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_GMV1] = {
-               /* Adrian Cox <adrian@humboldt.co.uk */
-               .name           = "AG Electronics GMV1",
-               .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 1,
-               .gpiomask       = 0xF,
-               .muxsel         = { 2, 2 },
-               .audiomux       = { },
-               .no_msp34xx     = 1,
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_BESTBUY_EASYTV2] = {
-               /* Miguel Angel Alvarez <maacruz@navegalia.com>
-               new Easy TV BT878 version (model CPH061)
-               special thanks to Informatica Mieres for providing the card */
-               .name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
-               .video_inputs   = 3,
-               .audio_inputs   = 2,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xFF,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 1, 0, 4, 4, 9 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_ATI_TVWONDER] = {
-               /* Lukas Gebauer <geby@volny.cz> */
-               .name           = "ATI TV-Wonder",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xf03f,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 0xbffe, 0, 0xbfff, 0, 0xbffe },
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x40 ---------------------------------- */
-       [BTTV_BOARD_ATI_TVWONDERVE] = {
-               /* Lukas Gebauer <geby@volny.cz> */
-               .name           = "ATI TV-Wonder VE",
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 1,
-               .muxsel         = { 2, 3, 0, 1 },
-               .audiomux       = { 0, 0, 1, 0, 0 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_FLYVIDEO2000] = {
-               /* DeeJay <deejay@westel900.net (2000S) */
-               .name           = "Lifeview FlyVideo 2000S LR90",
-               .video_inputs   = 3,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x18e0,
-               .muxsel         = { 2, 3, 0, 1 },
-                               /* Radio changed from 1e80 to 0x800 to make
-                               FlyVideo2000S in .hu happy (gm)*/
-                               /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
-               .audiomux       = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
-               .audio_hook     = fv2000s_audio,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 5,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_TERRATVALUER] = {
-               .name           = "Terratec TValueRadio",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0xffff00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x500, 0x500, 0x300, 0x900, 0x900 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_GVBCTV4PCI] = {
-               /* TANAKA Kei <peg00625@nifty.com> */
-               .name           = "IODATA GV-BCTV4/PCI",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x010f00,
-               .muxsel         = {2, 3, 0, 0 },
-               .audiomux       = {0x10000, 0, 0x10000, 0, 0, 0 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = gvbctv3pci_audio,
-       },
-
-       /* ---- card 0x44 ---------------------------------- */
-       [BTTV_BOARD_VOODOOTV_FM] = {
-               .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
-               /* try "insmod msp3400 simple=0" if you have
-               * sound problems with this card. */
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 0x4f8a00,
-               /* 0x100000: 1=MSP enabled (0=disable again)
-               * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
-               .audiomux       = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
-               /* tvtuner, radio,   external,internal, mute,  stereo
-               * tuner, Composit, SVid, Composit-on-Svid-adapter */
-               .muxsel         = { 2, 3 ,0 ,1 },
-               .tuner_type     = TUNER_MT2032,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_AIMMS] = {
-               /* Philip Blundell <pb@nexus.co.uk> */
-               .name           = "Active Imaging AIMMS",
-               .video_inputs   = 1,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .muxsel         = { 2 },
-               .gpiomask       = 0
-       },
-       [BTTV_BOARD_PV_BT878P_PLUS] = {
-               /* Tomasz Pyra <hellfire@sedez.iq.pl> */
-               .name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
-               .video_inputs   = 3,
-               .audio_inputs   = 4,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0, 11, 7, 13, 0 }, /* TV and Radio with same GPIO ! */
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 25,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-               /* GPIO wiring:
-                       GPIO0: U4.A0 (hef4052bt)
-                       GPIO1: U4.A1
-                       GPIO2: U4.A1 (second hef4052bt)
-                       GPIO3: U4.nEN, U5.A0, A5.nEN
-                       GPIO8-15: vrd866b ?
-               */
-       },
-       [BTTV_BOARD_FLYVIDEO98EZ] = {
-               .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
-               .pll            = PLL_28,
-               .no_msp34xx     = 1,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-       /* ---- card 0x48 ---------------------------------- */
-       [BTTV_BOARD_PV_BT878P_9B] = {
-               /* Dariusz Kowalewski <darekk@automex.pl> */
-               .name           = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x3f,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
-               .needs_tvaudio  = 1,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 5,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
-               .has_radio      = 1,  /* Note: not all cards have radio */
-               .has_remote     = 1,
-               /* GPIO wiring:
-                       GPIO0: A0 hef4052
-                       GPIO1: A1 hef4052
-                       GPIO3: nEN hef4052
-                       GPIO8-15: vrd866b
-                       GPIO20,22,23: R30,R29,R28
-               */
-       },
-       [BTTV_BOARD_SENSORAY311] = {
-               /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
-               /* you must jumper JP5 for the card to work */
-               .name           = "Sensoray 311",
-               .video_inputs   = 5,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 4,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0, 0 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_RV605] = {
-               /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
-               .name           = "RemoteVision MX (RV605)",
-               .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0x00,
-               .gpiomask2      = 0x07ff,
-               .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
-                               0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .muxsel_hook    = rv605_muxsel,
-       },
-       [BTTV_BOARD_POWERCLR_MTV878] = {
-               .name           = "Powercolor MTV878/ MTV878R/ MTV878F",
-               .video_inputs   = 3,
-               .audio_inputs   = 2,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
-               .muxsel         = { 2, 1, 1, },
-               .audiomux       = { 0, 1, 2, 2, 4 },
-               .needs_tvaudio  = 0,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .has_radio      = 1,
-       },
-
-       /* ---- card 0x4c ---------------------------------- */
-       [BTTV_BOARD_WINDVR] = {
-               /* Masaki Suzuki <masaki@btree.org> */
-               .name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x140007,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 1, 2, 3, 4, 0 },
-               .tuner_type     = TUNER_PHILIPS_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = windvr_audio,
-       },
-       [BTTV_BOARD_GRANDTEC_MULTI] = {
-               .name           = "GrandTec Multi Capture Card (Bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_KWORLD] = {
-               .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
-               .video_inputs   = 4,
-               .audio_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
-               .audiomux       = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
-                                               * This card lacks external Audio In, so we mute it on Ext. & Int.
-                                               * The PCB can take a sbx1637/sbx1673, wiring unknown.
-                                               * This card lacks PCI subsystem ID, sigh.
-                                               * audiomux=1: lower volume, 2+3: mute
-                                               * btwincap uses 0x80000/0x80003
-                                               */
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 5,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
-               radio signal strength indicators work fine. */
-               .has_radio      = 1,
-               /* GPIO Info:
-                       GPIO0,1:   HEF4052 A0,A1
-                       GPIO2:     HEF4052 nENABLE
-                       GPIO3-7:   n.c.
-                       GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
-                       GPIO14,15: ??
-                       GPIO16-21: n.c.
-                       GPIO22,23: ??
-                       ??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
-       },
-       [BTTV_BOARD_DSP_TCVIDEO] = {
-               /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
-               .name           = "DSP Design TCVIDEO",
-               .video_inputs   = 4,
-               .svhs           = -1,
-               .muxsel         = { 2, 3, 1, 0 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-               /* ---- card 0x50 ---------------------------------- */
-       [BTTV_BOARD_HAUPPAUGEPVR] = {
-               .name           = "Hauppauge WinTV PVR",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 0, 1, 1 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-
-               .gpiomask       = 7,
-               .audiomux       = {7},
-       },
-       [BTTV_BOARD_GVBCTV5PCI] = {
-               .name           = "IODATA GV-BCTV5/PCI",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x0f0f80,
-               .muxsel         = {2, 3, 1, 0 },
-               .audiomux       = {0x030000, 0x010000, 0, 0, 0x020000, 0},
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_NTSC_M,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = gvbctv5pci_audio,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_OSPREY1x0] = {
-               .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
-               .video_inputs   = 4,                  /* id-inputs-clock */
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 3,
-               .muxsel         = { 3, 2, 0, 1 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY1x0_848] = {
-               .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
-               .video_inputs   = 3,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-
-               /* ---- card 0x54 ---------------------------------- */
-       [BTTV_BOARD_OSPREY101_848] = {
-               .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
-               .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 3, 1 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY1x1] = {
-               .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
-               .video_inputs   = 1,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .muxsel         = { 0 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY1x1_SVID] = {
-               .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
-               .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 0, 1 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY2xx] = {
-               .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
-               .video_inputs   = 1,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
-               .muxsel         = { 0 },
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-
-               /* ---- card 0x58 ---------------------------------- */
-       [BTTV_BOARD_OSPREY2x0_SVID] = {
-               .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 0, 1 },
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY2x0] = {
-               .name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 2, 3 },
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY500] = {
-               .name           = "Osprey 500",   /* 500 */
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 2, 3 },
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-       [BTTV_BOARD_OSPREY540] = {
-               .name           = "Osprey 540",   /* 540 */
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-       #if 0 /* TODO ... */
-               .svhs           = OSPREY540_SVID_ANALOG,
-               .muxsel         = {       [OSPREY540_COMP_ANALOG] = 2,
-                                       [OSPREY540_SVID_ANALOG] = 3, },
-       #endif
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       #if 0 /* TODO ... */
-               .muxsel_hook    = osprey_540_muxsel,
-               .picture_hook   = osprey_540_set_picture,
-       #endif
-       },
-
-               /* ---- card 0x5C ---------------------------------- */
-       [BTTV_BOARD_OSPREY2000] = {
-               .name           = "Osprey 2000",  /* 2000 */
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 2, 3 },
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
-       },
-       [BTTV_BOARD_IDS_EAGLE] = {
-               /* M G Berberich <berberic@forwiss.uni-passau.de> */
-               .name           = "IDS Eagle",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
-               .gpiomask       = 0,
-               .muxsel         = { 0, 1, 2, 3 },
-               .muxsel_hook    = eagle_muxsel,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .pll            = PLL_28,
-       },
-       [BTTV_BOARD_PINNACLESAT] = {
-               .name           = "Pinnacle PCTV Sat",
-               .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .svhs           = 1,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .muxsel         = { 3, 0, 1, 2 },
-               .pll            = PLL_28,
-               .no_gpioirq     = 1,
-               .has_dvb        = 1,
-       },
-       [BTTV_BOARD_FORMAC_PROTV] = {
-               .name           = "Formac ProTV II (bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 3,
-               .gpiomask       = 2,
-               /* TV, Comp1, Composite over SVID con, SVID */
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 2, 2, 0, 0, 0 },
-               .pll            = PLL_28,
-               .has_radio      = 1,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       /* sound routing:
-               GPIO=0x00,0x01,0x03: mute (?)
-               0x02: both TV and radio (tuner: FM1216/I)
-               The card has onboard audio connectors labeled "cdrom" and "board",
-               not soldered here, though unknown wiring.
-               Card lacks: external audio in, pci subsystem id.
-       */
-       },
-
-               /* ---- card 0x60 ---------------------------------- */
-       [BTTV_BOARD_MACHTV] = {
-               .name           = "MachTV",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1},
-               .audiomux       = { 0, 1, 2, 3, 4},
-               .needs_tvaudio  = 1,
-               .tuner_type     = 5,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-       },
-       [BTTV_BOARD_EURESYS_PICOLO] = {
-               .name           = "Euresys Picolo",
-               .video_inputs   = 3,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = 2,
-               .gpiomask       = 0,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .muxsel         = { 2, 0, 1},
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_PV150] = {
-               /* Luc Van Hoeylandt <luc@e-magic.be> */
-               .name           = "ProVideo PV150", /* 0x4f */
-               .video_inputs   = 2,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_AD_TVK503] = {
-               /* Hiroshi Takekawa <sian@big.or.jp> */
-               /* This card lacks subsystem ID */
-               .name           = "AD-TVK503", /* 0x63 */
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x001e8007,
-               .muxsel         = { 2, 3, 1, 0 },
-               /*                  Tuner, Radio, external, internal, off,  on */
-               .audiomux       = { 0x08,  0x0f,  0x0a,     0x08,     0x0f, 0x08 },
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 2,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .audio_hook     = adtvk503_audio,
-       },
-
-               /* ---- card 0x64 ---------------------------------- */
-       [BTTV_BOARD_HERCULES_SM_TV] = {
-               .name           = "Hercules Smart TV Stereo",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .needs_tvaudio  = 1,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 5,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               /* Notes:
-               - card lacks subsystem ID
-               - stereo variant w/ daughter board with tda9874a @0xb0
-               - Audio Routing:
-                       always from tda9874 independent of GPIO (?)
-                       external line in: unknown
-               - Other chips: em78p156elp @ 0x96 (probably IR remote control)
-                       hef4053 (instead 4052) for unknown function
-               */
-       },
-       [BTTV_BOARD_PACETV] = {
-               .name           = "Pace TV & Radio Card",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 1 }, /* Tuner, CVid, SVid, CVid over SVid connector */
-               .gpiomask       = 0,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .tuner_type     = 1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-               .pll            = PLL_28,
-               /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
-               only internal line out: (4pin header) RGGL
-               Radio must be decoded by msp3410d (not routed through)*/
-               /*
-               .digital_mode   = DIGITAL_MODE_CAMERA,  todo!
-               */
-       },
-       [BTTV_BOARD_IVC200] = {
-               /* Chris Willing <chris@vislab.usyd.edu.au> */
-               .name           = "IVC-200",
-               .video_inputs   = 1,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
-               .gpiomask       = 0xdf,
-               .muxsel         = { 2 },
-               .pll            = PLL_28,
-       },
-       [BTTV_BOARD_XGUARD] = {
-               .name           = "Grand X-Guard / Trust 814PCI",
-               .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .tuner_type     = 4,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .gpiomask2      = 0xff,
-               .muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
-               .muxsel_hook    = xguard_muxsel,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .pll            = PLL_28,
-       },
-
-               /* ---- card 0x68 ---------------------------------- */
-       [BTTV_BOARD_NEBULA_DIGITV] = {
-               .name           = "Nebula Electronics DigiTV",
-               .video_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = -1,
-               .muxsel         = { 2, 3, 1, 0 },
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_dvb        = 1,
-               .has_remote     = 1,
-               .gpiomask       = 0x1b,
-               .no_gpioirq     = 1,
-       },
-       [BTTV_BOARD_PV143] = {
-               /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
-               .name           = "ProVideo PV143",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 0 },
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_VD009X1_MINIDIN] = {
-               /* M.Klahr@phytec.de */
-               .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
-               .svhs           = 3,
-               .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1, 0 },
-               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_VD009X1_COMBI] = {
-               .name           = "PHYTEC VD-009-X1 Combi (bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
-               .svhs           = 3,
-               .gpiomask       = 0x00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-
-               /* ---- card 0x6c ---------------------------------- */
-       [BTTV_BOARD_VD009_MINIDIN] = {
-               .name           = "PHYTEC VD-009 MiniDIN (bt878)",
-               .video_inputs   = 10,
-               .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
-               .svhs           = 9,
-               .gpiomask       = 0x00,
-               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-                                       via the upper nibble of muxsel. here: used for
-                                       xternal video-mux */
-               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
-               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_VD009_COMBI] = {
-               .name           = "PHYTEC VD-009 Combi (bt878)",
-               .video_inputs   = 10,
-               .audio_inputs   = 0,
-               .tuner          = -1, /* card has no tuner */
-               .svhs           = 9,
-               .gpiomask       = 0x00,
-               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-                                       via the upper nibble of muxsel. here: used for
-                                       xternal video-mux */
-               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
-               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_IVC100] = {
-               .name           = "IVC-100",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
-               .gpiomask       = 0xdf,
-               .muxsel         = { 2, 3, 1, 0 },
-               .pll            = PLL_28,
-       },
-       [BTTV_BOARD_IVC120] = {
-               /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
-               .name           = "IVC-120G",
-               .video_inputs   = 16,
-               .audio_inputs   = 0,    /* card has no audio */
-               .tuner          = -1,   /* card has no tuner */
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,   /* card has no svhs */
-               .needs_tvaudio  = 0,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .gpiomask       = 0x00,
-               .muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
-               .muxsel_hook    = ivc120_muxsel,
-               .pll            = PLL_28,
-       },
-
-               /* ---- card 0x70 ---------------------------------- */
-       [BTTV_BOARD_PC_HDTV] = {
-               .name           = "pcHDTV HD-2000 TV",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = TUNER_PHILIPS_ATSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_dvb        = 1,
-       },
-       [BTTV_BOARD_TWINHAN_DST] = {
-               .name           = "Twinhan DST + clones",
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .tuner_type     = TUNER_ABSENT,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_video       = 1,
-               .has_dvb        = 1,
-       },
-       [BTTV_BOARD_WINFASTVC100] = {
-               .name           = "Winfast VC100",
-               .video_inputs   = 3,
-               .audio_inputs   = 0,
-               .svhs           = 1,
-               .tuner          = -1,
-               .muxsel         = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .tuner_type     = TUNER_ABSENT,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-       },
-       [BTTV_BOARD_TEV560] = {
-               .name           = "Teppro TEV-560/InterVision IV-560",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 3,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 1, 1, 1, 1, 0 },
-               .needs_tvaudio  = 1,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_35,
-       },
-
-               /* ---- card 0x74 ---------------------------------- */
-       [BTTV_BOARD_SIMUS_GVC1100] = {
-               .name           = "SIMUS GVC1100",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .muxsel         = { 2, 2, 2, 2 },
-               .gpiomask       = 0x3F,
-               .muxsel_hook    = gvc1100_muxsel,
-       },
-       [BTTV_BOARD_NGSTV_PLUS] = {
-               /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
-               .name           = "NGS NGSTV+",
-               .video_inputs   = 3,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x008007,
-               .muxsel         = { 2, 3, 0, 0 },
-               .audiomux       = { 0, 0, 0, 0, 0x000003, 0 },
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-       },
-       [BTTV_BOARD_LMLBT4] = {
-               /* http://linuxmedialabs.com */
-               .name           = "LMLBT4",
-               .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .muxsel         = { 2, 3, 1, 0 },
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .needs_tvaudio  = 0,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_TEKRAM_M205] = {
-               /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
-               .name           = "Tekram M205 PRO",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = 2,
-               .needs_tvaudio  = 0,
-               .gpiomask       = 0x68,
-               .muxsel         = { 2, 3, 1 },
-               .audiomux       = { 0x68, 0x68, 0x61, 0x61, 0x00 },
-               .pll            = PLL_28,
-       },
-
-               /* ---- card 0x78 ---------------------------------- */
-       [BTTV_BOARD_CONTVFMI] = {
-               /* Javier Cendan Ares <jcendan@lycos.es> */
-               /* bt878 TV + FM without subsystem ID */
-               .name           = "Conceptronic CONTVFMi",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x008007,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 1, 2, 2, 3 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_PICOLO_TETRA_CHIP] = {
-               /*Eric DEBIEF <debief@telemsa.com>*/
-               /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
-               /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
-               /*0x79 in bttv.h*/
-               .name           = "Euresys Picolo Tetra",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0,
-               .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
-               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-               .pll            = PLL_28,
-               .needs_tvaudio  = 0,
-               .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_SPIRIT_TV] = {
-               /* Spirit TV Tuner from http://spiritmodems.com.au */
-               /* Stafford Goodsell <surge@goliath.homeunix.org> */
-               .name           = "Spirit TV Tuner",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x0000000f,
-               .muxsel         = { 2, 1, 1 },
-               .audiomux       = { 0x02, 0x00, 0x00, 0x00, 0x00 },
-               .tuner_type     = TUNER_TEMIC_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-       },
-       [BTTV_BOARD_AVDVBT_771] = {
-               /* Wolfram Joost <wojo@frokaschwei.de> */
-               .name           = "AVerMedia AVerTV DVB-T 771",
-               .video_inputs   = 2,
-               .svhs           = 1,
-               .tuner          = -1,
-               .tuner_type     = TUNER_ABSENT,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .muxsel         = { 3 , 3 },
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .pll            = PLL_28,
-               .has_dvb        = 1,
-               .no_gpioirq     = 1,
-               .has_remote     = 1,
-       },
-               /* ---- card 0x7c ---------------------------------- */
-       [BTTV_BOARD_AVDVBT_761] = {
-               /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
-               /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
-               .name           = "AverMedia AverTV DVB-T 761",
-               .video_inputs   = 2,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_dvb        = 1,
-               .no_gpioirq     = 1,
-               .has_remote     = 1,
-       },
-       [BTTV_BOARD_MATRIX_VISIONSQ] = {
-               /* andre.schwarz@matrix-vision.de */
-               .name             = "MATRIX Vision Sigma-SQ",
-               .video_inputs     = 16,
-               .audio_inputs     = 0,
-               .tuner            = -1,
-               .svhs             = -1,
-               .gpiomask         = 0x0,
-               .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
-                               3, 3, 3, 3, 3, 3, 3, 3 },
-               .muxsel_hook      = sigmaSQ_muxsel,
-               .audiomux         = { 0 },
-               .no_msp34xx       = 1,
-               .pll              = PLL_28,
-               .tuner_type       = -1,
-               .tuner_addr       = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MATRIX_VISIONSLC] = {
-               /* andre.schwarz@matrix-vision.de */
-               .name             = "MATRIX Vision Sigma-SLC",
-               .video_inputs     = 4,
-               .audio_inputs     = 0,
-               .tuner            = -1,
-               .svhs             = -1,
-               .gpiomask         = 0x0,
-               .muxsel           = { 2, 2, 2, 2 },
-               .muxsel_hook      = sigmaSLC_muxsel,
-               .audiomux         = { 0 },
-               .no_msp34xx       = 1,
-               .pll              = PLL_28,
-               .tuner_type       = -1,
-               .tuner_addr       = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-               /* BTTV_BOARD_APAC_VIEWCOMP */
-       [BTTV_BOARD_APAC_VIEWCOMP] = {
-               /* Attila Kondoros <attila.kondoros@chello.hu> */
-               /* bt878 TV + FM 0x00000000 subsystem ID */
-               .name           = "APAC Viewcomp 878(AMAX)",
-               .video_inputs   = 2,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = -1,
-               .gpiomask       = 0xFF,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 2, 0, 0, 0, 10 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
-               .has_radio      = 1,   /* not every card has radio */
-       },
-
-               /* ---- card 0x80 ---------------------------------- */
-       [BTTV_BOARD_DVICO_DVBT_LITE] = {
-               /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
-               .name           = "DViCO FusionHDTV DVB-T Lite",
-               .tuner          = -1,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .pll            = PLL_28,
-               .no_video       = 1,
-               .has_dvb        = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_VGEAR_MYVCD] = {
-               /* Steven <photon38@pchome.com.tw> */
-               .name           = "V-Gear MyVCD",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x3f,
-               .muxsel         = {2, 3, 1, 0 },
-               .audiomux       = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_PHILIPS_NTSC_M,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 0,
-       #if 0
-               .has_remote     = 1,
-       #endif
-       },
-       [BTTV_BOARD_SUPER_TV] = {
-               /* Rick C <cryptdragoon@gmail.com> */
-               .name           = "Super TV Tuner",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = TUNER_PHILIPS_NTSC,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .gpiomask       = 0x008007,
-               .audiomux       = { 0, 0x000001,0,0, 0 },
-               .needs_tvaudio  = 1,
-               .has_radio      = 1,
-       },
-       [BTTV_BOARD_TIBET_CS16] = {
-               /* Chris Fanning <video4linux@haydon.net> */
-               .name           = "Tibet Systems 'Progress DVR' CS16",
-               .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
-               .pll            = PLL_28,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .muxsel_hook    = tibetCS16_muxsel,
-       },
-       [BTTV_BOARD_KODICOM_4400R] = {
-               /* Bill Brack <wbrack@mmm.com.hk> */
-               /*
-               * Note that, because of the card's wiring, the "master"
-               * BT878A chip (i.e. the one which controls the analog switch
-               * and must use this card type) is the 2nd one detected.  The
-               * other 3 chips should use card type 0x85, whose description
-               * follows this one.  There is a EEPROM on the card (which is
-               * connected to the I2C of one of those other chips), but is
-               * not currently handled.  There is also a facility for a
-               * "monitor", which is also not currently implemented.
-               */
-               .name           = "Kodicom 4400R (master)",
-               .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
-               /* GPIO bits 0-9 used for analog switch:
-               *   00 - 03:    camera selector
-               *   04 - 06:    channel (controller) selector
-               *   07: data (1->on, 0->off)
-               *   08: strobe
-               *   09: reset
-               * bit 16 is input from sync separator for the channel
-               */
-               .gpiomask       = 0x0003ff,
-               .no_gpioirq     = 1,
-               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
-               .pll            = PLL_28,
-               .no_msp34xx     = 1,
-               .no_tda7432     = 1,
-               .no_tda9875     = 1,
-               .muxsel_hook    = kodicom4400r_muxsel,
-       },
-       [BTTV_BOARD_KODICOM_4400R_SL] = {
-               /* Bill Brack <wbrack@mmm.com.hk> */
-               /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
-               * one which controls the analog switch, and must use the card type)
-               * is the 2nd one detected.  The other 3 chips should use this card
-               * type
-               */
-               .name           = "Kodicom 4400R (slave)",
-               .video_inputs   = 16,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .svhs           = -1,
-               .gpiomask       = 0x010000,
-               .no_gpioirq     = 1,
-               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
-               .pll            = PLL_28,
-               .no_msp34xx     = 1,
-               .no_tda7432     = 1,
-               .no_tda9875     = 1,
-               .muxsel_hook    = kodicom4400r_muxsel,
-       },
-               /* ---- card 0x86---------------------------------- */
-       [BTTV_BOARD_ADLINK_RTV24] = {
-               /* Michael Henson <mhenson@clarityvi.com> */
-               /* Adlink RTV24 with special unlock codes */
-               .name           = "Adlink RTV24",
-               .video_inputs   = 4,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1, 0 },
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-       },
-               /* ---- card 0x87---------------------------------- */
-       [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
-               /* Michael Krufky <mkrufky@m1k.net> */
-               .name           = "DViCO FusionHDTV 5 Lite",
-               .tuner          = 0,
-               .tuner_type     = TUNER_LG_TDVS_H062F,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .svhs           = 2,
-               .muxsel         = { 2, 3, 1 },
-               .gpiomask       = 0x00e00007,
-               .audiomux       = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .has_dvb        = 1,
-       },
-               /* ---- card 0x88---------------------------------- */
-       [BTTV_BOARD_ACORP_Y878F] = {
-               /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
-               .name           = "Acorp Y878F",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x01fe00,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_YMEC_TVF66T5_B_DFF,
-               .tuner_addr     = 0xc1 >>1,
-               .radio_addr     = 0xc1 >>1,
-               .has_radio      = 1,
-       },
-               /* ---- card 0x89 ---------------------------------- */
-       [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
-               .name           = "Conceptronic CTVFMi v2",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x001c0007,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 1, 2, 2, 3 },
-               .needs_tvaudio  = 0,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TENA_9533_DI,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote     = 1,
-               .has_radio      = 1,
-       },
-               /* ---- card 0x8a ---------------------------------- */
-       [BTTV_BOARD_PV_BT878P_2E] = {
-               .name          = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
-               .video_inputs  = 5,
-               .audio_inputs  = 1,
-               .tuner         = 0,
-               .svhs          = 3,
-               .gpiomask      = 0x01fe00,
-               .muxsel        = { 2,3,1,1,-1 },
-               .digital_mode  = DIGITAL_MODE_CAMERA,
-               .audiomux      = { 0x00400, 0x10400, 0x04400, 0x80000, 0x12400, 0x46000  },
-               .no_msp34xx    = 1,
-               .pll           = PLL_28,
-               .tuner_type    = TUNER_LG_PAL_FM,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_remote    = 1,
-       },
-               /* ---- card 0x8b ---------------------------------- */
-       [BTTV_BOARD_PV_M4900] = {
-               /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
-               .name           = "Prolink PixelView PlayTV MPEG2 PV-M4900",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x3f,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
-               .no_msp34xx     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_YMEC_TVF_5533MF,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-               .has_remote     = 1,
-       },
-               /* ---- card 0x8c ---------------------------------- */
-       [BTTV_BOARD_OSPREY440]  = {
-               .name           = "Osprey 440",
-               .video_inputs   = 1,
-               .audio_inputs   = 1,
-               .tuner          = -1,
-               .svhs           = 1,
-               .muxsel         = { 2 },
-               .pll            = PLL_28,
-               .tuner_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-       },
-               /* ---- card 0x8d ---------------------------------- */
-       [BTTV_BOARD_ASOUND_SKYEYE] = {
-               .name           = "Asound Skyeye PCTV",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 15,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 2, 0, 0, 0, 1 },
-               .needs_tvaudio  = 1,
-               .pll            = PLL_28,
-               .tuner_type     = 2,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-               /* ---- card 0x8e ---------------------------------- */
-       [BTTV_BOARD_SABRENT_TVFM] = {
-               .name           = "Sabrent TV-FM (bttv version)",
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 0x108007,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 100000, 100002, 100002, 100000 },
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .pll            = PLL_28,
-               .tuner_type     = TUNER_TNF_5335MF,
-               .tuner_addr     = ADDR_UNSET,
-               .has_radio      = 1,
-       },
-       /* ---- card 0x8f ---------------------------------- */
-       [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = {
-               .name           = "Hauppauge ImpactVCB (bt878)",
-               .video_inputs   = 4,
-               .audio_inputs   = 0,
-               .tuner          = -1,
-               .svhs           = -1,
-               .gpiomask       = 0x0f, /* old: 7 */
-               .muxsel         = { 0, 1, 3, 2 }, /* Composite 0-3 */
-               .no_msp34xx     = 1,
-               .no_tda9875     = 1,
-               .no_tda7432     = 1,
-               .tuner_type     = -1,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-       },
-       [BTTV_BOARD_MACHTV_MAGICTV] = {
-               /* Julian Calaby <julian.calaby@gmail.com>
-                * Slightly different from original MachTV definition (0x60)
-
-                * FIXME: RegSpy says gpiomask should be "0x001c800f", but it
-                * stuffs up remote chip. Bug is a pin on the jaecs is not set
-                * properly (methinks) causing no keyup bits being set */
-
-               .name           = "MagicTV", /* rebranded MachTV */
-               .video_inputs   = 3,
-               .audio_inputs   = 1,
-               .tuner          = 0,
-               .svhs           = 2,
-               .gpiomask       = 7,
-               .muxsel         = { 2, 3, 1, 1 },
-               .audiomux       = { 0, 1, 2, 3, 4 },
-               .tuner_type     = TUNER_TEMIC_4009FR5_PAL,
-               .tuner_addr     = ADDR_UNSET,
-               .radio_addr     = ADDR_UNSET,
-               .pll            = PLL_28,
-               .has_radio      = 1,
-               .has_remote     = 1,
-       },
-};
-
-static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
-
-/* ----------------------------------------------------------------------- */
-
-static unsigned char eeprom_data[256];
-
-/*
- * identify card
- */
-void __devinit bttv_idcard(struct bttv *btv)
-{
-       unsigned int gpiobits;
-       int i,type;
-       unsigned short tmp;
-
-       /* read PCI subsystem ID */
-       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp);
-       btv->cardid = tmp << 16;
-       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
-       btv->cardid |= tmp;
-
-       if (0 != btv->cardid && 0xffffffff != btv->cardid) {
-               /* look for the card */
-               for (type = -1, i = 0; cards[i].id != 0; i++)
-                       if (cards[i].id  == btv->cardid)
-                               type = i;
-
-               if (type != -1) {
-                       /* found it */
-                       printk(KERN_INFO "bttv%d: detected: %s [card=%d], "
-                              "PCI subsystem ID is %04x:%04x\n",
-                              btv->c.nr,cards[type].name,cards[type].cardnr,
-                              btv->cardid & 0xffff,
-                              (btv->cardid >> 16) & 0xffff);
-                       btv->c.type = cards[type].cardnr;
-               } else {
-                       /* 404 */
-                       printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
-                              btv->c.nr, btv->cardid & 0xffff,
-                              (btv->cardid >> 16) & 0xffff);
-                       printk(KERN_DEBUG "please mail id, board name and "
-                              "the correct card= insmod option to video4linux-list@redhat.com\n");
-               }
-       }
-
-       /* let the user override the autodetected type */
-       if (card[btv->c.nr] < bttv_num_tvcards)
-               btv->c.type=card[btv->c.nr];
-
-       /* print which card config we are using */
-       printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr,
-              bttv_tvcards[btv->c.type].name, btv->c.type,
-              card[btv->c.nr] < bttv_num_tvcards
-              ? "insmod option" : "autodetected");
-
-       /* overwrite gpio stuff ?? */
-       if (UNSET == audioall && UNSET == audiomux[0])
-               return;
-
-       if (UNSET != audiomux[0]) {
-               gpiobits = 0;
-               for (i = 0; i < 5; i++) {
-                       bttv_tvcards[btv->c.type].audiomux[i] = audiomux[i];
-                       gpiobits |= audiomux[i];
-               }
-       } else {
-               gpiobits = audioall;
-               for (i = 0; i < 5; i++) {
-                       bttv_tvcards[btv->c.type].audiomux[i] = audioall;
-               }
-       }
-       bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
-       printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
-              btv->c.nr,bttv_tvcards[btv->c.type].gpiomask);
-       for (i = 0; i < 5; i++) {
-               printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].audiomux[i]);
-       }
-       printk("\n");
-}
-
-/*
- * (most) board specific initialisations goes here
- */
-
-/* Some Modular Technology cards have an eeprom, but no subsystem ID */
-static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
-{
-       int type = -1;
-
-       if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
-               type = BTTV_BOARD_MODTEC_205;
-       else if (0 == strncmp(eeprom_data+20,"Picolo",7))
-               type = BTTV_BOARD_EURESYS_PICOLO;
-       else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
-               type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
-
-       if (-1 != type) {
-               btv->c.type = type;
-               printk("bttv%d: detected by eeprom: %s [card=%d]\n",
-                      btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type);
-       }
-}
-
-static void flyvideo_gpio(struct bttv *btv)
-{
-       int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
-       int tuner=-1,ttype;
-
-       gpio_inout(0xffffff, 0);
-       udelay(8);  /* without this we would see the 0x1800 mask */
-       gpio = gpio_read();
-       /* FIXME: must restore OUR_EN ??? */
-
-       /* all cards provide GPIO info, some have an additional eeprom
-        * LR50: GPIO coding can be found lower right CP1 .. CP9
-        *       CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1.
-        *       GPIO14-12: n.c.
-        * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878)
-
-        * lowest 3 bytes are remote control codes (no handshake needed)
-        * xxxFFF: No remote control chip soldered
-        * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
-        * Note: Some bits are Audio_Mask !
-        */
-       ttype=(gpio&0x0f0000)>>16;
-       switch(ttype) {
-       case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
-               break;
-       case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
-               break;
-       case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
-               break;
-       case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */
-               break;
-               case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
-               break;
-       default:
-               printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
-       }
-
-       has_remote          =   gpio & 0x800000;
-       has_radio           =   gpio & 0x400000;
-       /*   unknown                   0x200000;
-        *   unknown2                  0x100000; */
-       is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
-       has_tda9820_tda9821 = !(gpio & 0x004000);
-       is_lr90             = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
-       /*
-        * gpio & 0x001000    output bit for audio routing */
-
-       if(is_capture_only)
-               tuner=4; /* No tuner present */
-
-       printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
-              btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
-       printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
-               btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
-               is_capture_only?"yes":"no ");
-
-       if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
-               btv->tuner_type = tuner;
-       btv->has_radio = has_radio;
-
-       /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
-        * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
-        * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
-       if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
-       /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
-}
-
-static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
-                              14,2,17,1, 4,1,4,3,  1,2,16,1, 4,4,4,4 };
-static int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
-                              1,1,1,1,   1,1,1,0,  0,0,0,0,  0,1,0,0 };
-
-static void miro_pinnacle_gpio(struct bttv *btv)
-{
-       int id,msp,gpio;
-       char *info;
-
-       gpio_inout(0xffffff, 0);
-       gpio = gpio_read();
-       id   = ((gpio>>10) & 63) -1;
-       msp  = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
-       if (id < 32) {
-               btv->tuner_type = miro_tunermap[id];
-               if (0 == (gpio & 0x20)) {
-                       btv->has_radio = 1;
-                       if (!miro_fmtuner[id]) {
-                               btv->has_matchbox = 1;
-                               btv->mbox_we    = (1<<6);
-                               btv->mbox_most  = (1<<7);
-                               btv->mbox_clk   = (1<<8);
-                               btv->mbox_data  = (1<<9);
-                               btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
-                       }
-               } else {
-                       btv->has_radio = 0;
-               }
-               if (-1 != msp) {
-                       if (btv->c.type == BTTV_BOARD_MIRO)
-                               btv->c.type = BTTV_BOARD_MIROPRO;
-                       if (btv->c.type == BTTV_BOARD_PINNACLE)
-                               btv->c.type = BTTV_BOARD_PINNACLEPRO;
-               }
-               printk(KERN_INFO
-                      "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
-                      btv->c.nr, id+1, btv->tuner_type,
-                      !btv->has_radio ? "no" :
-                      (btv->has_matchbox ? "matchbox" : "fmtuner"),
-                      (-1 == msp) ? "no" : "yes");
-       } else {
-               /* new cards with microtune tuner */
-               id = 63 - id;
-               btv->has_radio = 0;
-               switch (id) {
-               case 1:
-                       info = "PAL / mono";
-                       btv->tda9887_conf = TDA9887_INTERCARRIER;
-                       break;
-               case 2:
-                       info = "PAL+SECAM / stereo";
-                       btv->has_radio = 1;
-                       btv->tda9887_conf = TDA9887_QSS;
-                       break;
-               case 3:
-                       info = "NTSC / stereo";
-                       btv->has_radio = 1;
-                       btv->tda9887_conf = TDA9887_QSS;
-                       break;
-               case 4:
-                       info = "PAL+SECAM / mono";
-                       btv->tda9887_conf = TDA9887_QSS;
-                       break;
-               case 5:
-                       info = "NTSC / mono";
-                       btv->tda9887_conf = TDA9887_INTERCARRIER;
-                       break;
-               case 6:
-                       info = "NTSC / stereo";
-                       btv->tda9887_conf = TDA9887_INTERCARRIER;
-                       break;
-               case 7:
-                       info = "PAL / stereo";
-                       btv->tda9887_conf = TDA9887_INTERCARRIER;
-                       break;
-               default:
-                       info = "oops: unknown card";
-                       break;
-               }
-               if (-1 != msp)
-                       btv->c.type = BTTV_BOARD_PINNACLEPRO;
-               printk(KERN_INFO
-                      "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
-                      btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
-               btv->tuner_type = TUNER_MT2032;
-       }
-}
-
-/* GPIO21   L: Buffer aktiv, H: Buffer inaktiv */
-#define LM1882_SYNC_DRIVE     0x200000L
-
-static void init_ids_eagle(struct bttv *btv)
-{
-       gpio_inout(0xffffff,0xFFFF37);
-       gpio_write(0x200020);
-
-       /* flash strobe inverter ?! */
-       gpio_write(0x200024);
-
-       /* switch sync drive off */
-       gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
-
-       /* set BT848 muxel to 2 */
-       btaor((2)<<5, ~(2<<5), BT848_IFORM);
-}
-
-/* Muxsel helper for the IDS Eagle.
- * the eagles does not use the standard muxsel-bits but
- * has its own multiplexer */
-static void eagle_muxsel(struct bttv *btv, unsigned int input)
-{
-       btaor((2)<<5, ~(3<<5), BT848_IFORM);
-       gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
-
-       /* composite */
-       /* set chroma ADC to sleep */
-       btor(BT848_ADC_C_SLEEP, BT848_ADC);
-       /* set to composite video */
-       btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
-       btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
-
-       /* switch sync drive off */
-       gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
-}
-
-static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
-{
-       static const int masks[] = {0x30, 0x01, 0x12, 0x23};
-       gpio_write(masks[input%4]);
-}
-
-/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and
-   alarms output
-
-   GPIObit    | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
-   assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1|   |   |
-
-   IN - sensor inputs, INx - sensor inputs and TI XORed together
-   O1,O2,O3 - alarm outputs (relays)
-
-   OUT ENABLE   1    1   0  . 1  1   0   0 . 0   0   0    0   = 0x6C0
-
-*/
-
-static void init_lmlbt4x(struct bttv *btv)
-{
-       printk(KERN_DEBUG "LMLBT4x init\n");
-       btwrite(0x000000, BT848_GPIO_REG_INP);
-       gpio_inout(0xffffff, 0x0006C0);
-       gpio_write(0x000000);
-}
-
-static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input)
-{
-       unsigned int inmux = input % 8;
-       gpio_inout( 0xf, 0xf );
-       gpio_bits( 0xf, inmux );
-}
-
-static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input)
-{
-       unsigned int inmux = input % 4;
-       gpio_inout( 3<<9, 3<<9 );
-       gpio_bits( 3<<9, inmux<<9 );
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void bttv_reset_audio(struct bttv *btv)
-{
-       /*
-        * BT878A has a audio-reset register.
-        * 1. This register is an audio reset function but it is in
-        *    function-0 (video capture) address space.
-        * 2. It is enough to do this once per power-up of the card.
-        * 3. There is a typo in the Conexant doc -- it is not at
-        *    0x5B, but at 0x058. (B is an odd-number, obviously a typo!).
-        * --//Shrikumar 030609
-        */
-       if (btv->id != 878)
-               return;
-
-       if (bttv_debug)
-               printk("bttv%d: BT878A ARESET\n",btv->c.nr);
-       btwrite((1<<7), 0x058);
-       udelay(10);
-       btwrite(     0, 0x058);
-}
-
-/* initialization part one -- before registering i2c bus */
-void __devinit bttv_init_card1(struct bttv *btv)
-{
-       switch (btv->c.type) {
-       case BTTV_BOARD_HAUPPAUGE:
-       case BTTV_BOARD_HAUPPAUGE878:
-               boot_msp34xx(btv,5);
-               break;
-       case BTTV_BOARD_VOODOOTV_FM:
-               boot_msp34xx(btv,20);
-               break;
-       case BTTV_BOARD_AVERMEDIA98:
-               boot_msp34xx(btv,11);
-               break;
-       case BTTV_BOARD_HAUPPAUGEPVR:
-               pvr_boot(btv);
-               break;
-       case BTTV_BOARD_TWINHAN_DST:
-       case BTTV_BOARD_AVDVBT_771:
-       case BTTV_BOARD_PINNACLESAT:
-               btv->use_i2c_hw = 1;
-               break;
-       case BTTV_BOARD_ADLINK_RTV24:
-               init_RTV24( btv );
-               break;
-
-       }
-       if (!bttv_tvcards[btv->c.type].has_dvb)
-               bttv_reset_audio(btv);
-}
-
-/* initialization part two -- after registering i2c bus */
-void __devinit bttv_init_card2(struct bttv *btv)
-{
-       int tda9887;
-       int addr=ADDR_UNSET;
-
-       btv->tuner_type = -1;
-
-       if (BTTV_BOARD_UNKNOWN == btv->c.type) {
-               bttv_readee(btv,eeprom_data,0xa0);
-               identify_by_eeprom(btv,eeprom_data);
-       }
-
-       switch (btv->c.type) {
-       case BTTV_BOARD_MIRO:
-       case BTTV_BOARD_MIROPRO:
-       case BTTV_BOARD_PINNACLE:
-       case BTTV_BOARD_PINNACLEPRO:
-               /* miro/pinnacle */
-               miro_pinnacle_gpio(btv);
-               break;
-       case BTTV_BOARD_FLYVIDEO_98:
-       case BTTV_BOARD_MAXI:
-       case BTTV_BOARD_LIFE_FLYKIT:
-       case BTTV_BOARD_FLYVIDEO:
-       case BTTV_BOARD_TYPHOON_TVIEW:
-       case BTTV_BOARD_CHRONOS_VS2:
-       case BTTV_BOARD_FLYVIDEO_98FM:
-       case BTTV_BOARD_FLYVIDEO2000:
-       case BTTV_BOARD_FLYVIDEO98EZ:
-       case BTTV_BOARD_CONFERENCETV:
-       case BTTV_BOARD_LIFETEC_9415:
-               flyvideo_gpio(btv);
-               break;
-       case BTTV_BOARD_HAUPPAUGE:
-       case BTTV_BOARD_HAUPPAUGE878:
-       case BTTV_BOARD_HAUPPAUGEPVR:
-               /* pick up some config infos from the eeprom */
-               bttv_readee(btv,eeprom_data,0xa0);
-               hauppauge_eeprom(btv);
-               break;
-       case BTTV_BOARD_AVERMEDIA98:
-       case BTTV_BOARD_AVPHONE98:
-               bttv_readee(btv,eeprom_data,0xa0);
-               avermedia_eeprom(btv);
-               break;
-       case BTTV_BOARD_PXC200:
-               init_PXC200(btv);
-               break;
-       case BTTV_BOARD_PICOLO_TETRA_CHIP:
-               picolo_tetra_init(btv);
-               break;
-       case BTTV_BOARD_VHX:
-               btv->has_radio    = 1;
-               btv->has_matchbox = 1;
-               btv->mbox_we      = 0x20;
-               btv->mbox_most    = 0;
-               btv->mbox_clk     = 0x08;
-               btv->mbox_data    = 0x10;
-               btv->mbox_mask    = 0x38;
-               break;
-       case BTTV_BOARD_VOBIS_BOOSTAR:
-       case BTTV_BOARD_TERRATV:
-               terratec_active_radio_upgrade(btv);
-               break;
-       case BTTV_BOARD_MAGICTVIEW061:
-               if (btv->cardid == 0x3002144f) {
-                       btv->has_radio=1;
-                       printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
-               }
-               break;
-       case BTTV_BOARD_STB2:
-               if (btv->cardid == 0x3060121a) {
-                       /* Fix up entry for 3DFX VoodooTV 100,
-                          which is an OEM STB card variant. */
-                       btv->has_radio=0;
-                       btv->tuner_type=TUNER_TEMIC_NTSC;
-               }
-               break;
-       case BTTV_BOARD_OSPREY1x0:
-       case BTTV_BOARD_OSPREY1x0_848:
-       case BTTV_BOARD_OSPREY101_848:
-       case BTTV_BOARD_OSPREY1x1:
-       case BTTV_BOARD_OSPREY1x1_SVID:
-       case BTTV_BOARD_OSPREY2xx:
-       case BTTV_BOARD_OSPREY2x0_SVID:
-       case BTTV_BOARD_OSPREY2x0:
-       case BTTV_BOARD_OSPREY500:
-       case BTTV_BOARD_OSPREY540:
-       case BTTV_BOARD_OSPREY2000:
-               bttv_readee(btv,eeprom_data,0xa0);
-               osprey_eeprom(btv);
-               break;
-       case BTTV_BOARD_IDS_EAGLE:
-               init_ids_eagle(btv);
-               break;
-       case BTTV_BOARD_MODTEC_205:
-               bttv_readee(btv,eeprom_data,0xa0);
-               modtec_eeprom(btv);
-               break;
-       case BTTV_BOARD_LMLBT4:
-               init_lmlbt4x(btv);
-               break;
-       case BTTV_BOARD_TIBET_CS16:
-               tibetCS16_init(btv);
-               break;
-       case BTTV_BOARD_KODICOM_4400R:
-               kodicom4400r_init(btv);
-               break;
-       }
-
-       /* pll configuration */
-       if (!(btv->id==848 && btv->revision==0x11)) {
-               /* defaults from card list */
-               if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
-                       btv->pll.pll_ifreq=28636363;
-                       btv->pll.pll_crystal=BT848_IFORM_XT0;
-               }
-               if (PLL_35 == bttv_tvcards[btv->c.type].pll) {
-                       btv->pll.pll_ifreq=35468950;
-                       btv->pll.pll_crystal=BT848_IFORM_XT1;
-               }
-               /* insmod options can override */
-               switch (pll[btv->c.nr]) {
-               case 0: /* none */
-                       btv->pll.pll_crystal = 0;
-                       btv->pll.pll_ifreq   = 0;
-                       btv->pll.pll_ofreq   = 0;
-                       break;
-               case 1: /* 28 MHz */
-               case 28:
-                       btv->pll.pll_ifreq   = 28636363;
-                       btv->pll.pll_ofreq   = 0;
-                       btv->pll.pll_crystal = BT848_IFORM_XT0;
-                       break;
-               case 2: /* 35 MHz */
-               case 35:
-                       btv->pll.pll_ifreq   = 35468950;
-                       btv->pll.pll_ofreq   = 0;
-                       btv->pll.pll_crystal = BT848_IFORM_XT1;
-                       break;
-               }
-       }
-       btv->pll.pll_current = -1;
-
-       /* tuner configuration (from card list / autodetect / insmod option) */
-       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
-               addr = bttv_tvcards[btv->c.type].tuner_addr;
-
-       if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
-               if(UNSET == btv->tuner_type)
-                       btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
-       if (UNSET != tuner[btv->c.nr])
-               btv->tuner_type = tuner[btv->c.nr];
-       printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
-
-       if (btv->tuner_type != UNSET) {
-               struct tuner_setup tun_setup;
-
-               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
-               tun_setup.type = btv->tuner_type;
-               tun_setup.addr = addr;
-
-               bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
-       }
-
-       if (btv->tda9887_conf) {
-               bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
-                                                       &btv->tda9887_conf);
-       }
-
-       btv->svhs = bttv_tvcards[btv->c.type].svhs;
-       if (svhs[btv->c.nr] != UNSET)
-               btv->svhs = svhs[btv->c.nr];
-       if (remote[btv->c.nr] != UNSET)
-               btv->has_remote = remote[btv->c.nr];
-
-       if (bttv_tvcards[btv->c.type].has_radio)
-               btv->has_radio=1;
-       if (bttv_tvcards[btv->c.type].has_remote)
-               btv->has_remote=1;
-       if (!bttv_tvcards[btv->c.type].no_gpioirq)
-               btv->gpioirq=1;
-       if (bttv_tvcards[btv->c.type].audio_hook)
-               btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
-
-       if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
-               /* detect Bt832 chip for quartzsight digital camera */
-               if ((bttv_I2CRead(btv, I2C_BT832_ALT1, "Bt832") >=0) ||
-                   (bttv_I2CRead(btv, I2C_BT832_ALT2, "Bt832") >=0))
-                       boot_bt832(btv);
-       }
-
-       if (!autoload)
-               return;
-
-       /* try to detect audio/fader chips */
-       if (!bttv_tvcards[btv->c.type].no_msp34xx &&
-           bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0)
-               request_module("msp3400");
-
-       if (bttv_tvcards[btv->c.type].msp34xx_alt &&
-           bttv_I2CRead(btv, I2C_MSP3400_ALT, "MSP34xx (alternate address)") >=0)
-               request_module("msp3400");
-
-       if (!bttv_tvcards[btv->c.type].no_tda9875 &&
-           bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0)
-               request_module("tda9875");
-
-       if (!bttv_tvcards[btv->c.type].no_tda7432 &&
-           bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0)
-               request_module("tda7432");
-
-       if (bttv_tvcards[btv->c.type].needs_tvaudio)
-               request_module("tvaudio");
-
-       /* tuner modules */
-       tda9887 = 0;
-       if (btv->tda9887_conf)
-               tda9887 = 1;
-       if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
-           bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
-               tda9887 = 1;
-       /* Hybrid DVB card, DOES have a tda9887 */
-       if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
-               tda9887 = 1;
-       if((btv->tuner_type == TUNER_PHILIPS_FM1216ME_MK3) ||
-          (btv->tuner_type == TUNER_PHILIPS_FM1236_MK3) ||
-          (btv->tuner_type == TUNER_PHILIPS_FM1256_IH3) ||
-           tda9887)
-               request_module("tda9887");
-       if (btv->tuner_type != UNSET)
-               request_module("tuner");
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-static void modtec_eeprom(struct bttv *btv)
-{
-       if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
-               btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
-               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
-       } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
-               btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
-               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
-       } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
-               btv->tuner_type=TUNER_PHILIPS_NTSC;
-               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
-       } else {
-               printk("bttv%d: Modtec: Unknown TunerString: %s\n",
-                      btv->c.nr,&eeprom_data[0x1e]);
-       }
-}
-
-static void __devinit hauppauge_eeprom(struct bttv *btv)
-{
-       struct tveeprom tv;
-
-       tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data);
-       btv->tuner_type = tv.tuner_type;
-       btv->has_radio  = tv.has_radio;
-
-       printk("bttv%d: Hauppauge eeprom indicates model#%d\n",
-               btv->c.nr, tv.model);
-
-       /*
-        * Some of the 878 boards have duplicate PCI IDs. Switch the board
-        * type based on model #.
-        */
-       if(tv.model == 64900) {
-               printk("bttv%d: Switching board type from %s to %s\n",
-                       btv->c.nr,
-                       bttv_tvcards[btv->c.type].name,
-                       bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name);
-               btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB;
-       }
-}
-
-static int terratec_active_radio_upgrade(struct bttv *btv)
-{
-       int freq;
-
-       btv->has_radio    = 1;
-       btv->has_matchbox = 1;
-       btv->mbox_we      = 0x10;
-       btv->mbox_most    = 0x20;
-       btv->mbox_clk     = 0x08;
-       btv->mbox_data    = 0x04;
-       btv->mbox_mask    = 0x3c;
-
-       btv->mbox_iow     = 1 <<  8;
-       btv->mbox_ior     = 1 <<  9;
-       btv->mbox_csel    = 1 << 10;
-
-       freq=88000/62.5;
-       tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */
-       if (0x1ed8 == tea5757_read(btv)) {
-               printk("bttv%d: Terratec Active Radio Upgrade found.\n",
-                      btv->c.nr);
-               btv->has_radio    = 1;
-               btv->has_matchbox = 1;
-       } else {
-               btv->has_radio    = 0;
-               btv->has_matchbox = 0;
-       }
-       return 0;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * minimal bootstrap for the WinTV/PVR -- upload altera firmware.
- *
- * The hcwamc.rbf firmware file is on the Hauppauge driver CD.  Have
- * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be
- * unpacked with unzip).
- */
-#define PVR_GPIO_DELAY         10
-
-#define BTTV_ALT_DATA          0x000001
-#define BTTV_ALT_DCLK          0x100000
-#define BTTV_ALT_NCONFIG       0x800000
-
-static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
-{
-       u32 n;
-       u8 bits;
-       int i;
-
-       gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
-       gpio_write(0);
-       udelay(PVR_GPIO_DELAY);
-
-       gpio_write(BTTV_ALT_NCONFIG);
-       udelay(PVR_GPIO_DELAY);
-
-       for (n = 0; n < microlen; n++) {
-               bits = micro[n];
-               for ( i = 0 ; i < 8 ; i++ ) {
-                       gpio_bits(BTTV_ALT_DCLK,0);
-                       if (bits & 0x01)
-                               gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA);
-                       else
-                               gpio_bits(BTTV_ALT_DATA,0);
-                       gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK);
-                       bits >>= 1;
-               }
-       }
-       gpio_bits(BTTV_ALT_DCLK,0);
-       udelay(PVR_GPIO_DELAY);
-
-       /* begin Altera init loop (Not necessary,but doesn't hurt) */
-       for (i = 0 ; i < 30 ; i++) {
-               gpio_bits(BTTV_ALT_DCLK,0);
-               gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK);
-       }
-       gpio_bits(BTTV_ALT_DCLK,0);
-       return 0;
-}
-
-static int __devinit pvr_boot(struct bttv *btv)
-{
-       const struct firmware *fw_entry;
-       int rc;
-
-       rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
-       if (rc != 0) {
-               printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
-                      btv->c.nr);
-               return rc;
-       }
-       rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
-       printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
-              btv->c.nr, (rc < 0) ? "failed" : "ok");
-       release_firmware(fw_entry);
-       return rc;
-}
-
-/* ----------------------------------------------------------------------- */
-/* some osprey specific stuff                                              */
-
-static void __devinit osprey_eeprom(struct bttv *btv)
-{
-       int i = 0;
-       unsigned char *ee = eeprom_data;
-       unsigned long serial = 0;
-
-       if (btv->c.type == 0) {
-              /* this might be an antique... check for MMAC label in eeprom */
-              if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
-                      unsigned char checksum = 0;
-                      for (i =0; i<21; i++)
-                              checksum += ee[i];
-                      if (checksum != ee[21])
-                              return;
-                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
-                      for (i = 12; i < 21; i++)
-                              serial *= 10, serial += ee[i] - '0';
-              }
-       } else {
-              unsigned short type;
-              int offset = 4*16;
-
-              for(; offset < 8*16; offset += 16) {
-                      unsigned short checksum = 0;
-                      /* verify the checksum */
-                      for(i = 0; i<14; i++) checksum += ee[i+offset];
-                              checksum = ~checksum;  /* no idea why */
-                              if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
-                                  ((checksum & 0x0FF) == ee[offset+15])) {
-                              break;
-                      }
-              }
-
-              if (offset >= 8*16)
-                      return;
-
-              /* found a valid descriptor */
-              type = (ee[offset+4]<<8) | (ee[offset+5]);
-
-              switch(type) {
-
-              /* 848 based */
-              case 0x0004:
-                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
-                      break;
-              case 0x0005:
-                      btv->c.type = BTTV_BOARD_OSPREY101_848;
-                      break;
-
-              /* 878 based */
-              case 0x0012:
-              case 0x0013:
-                      btv->c.type = BTTV_BOARD_OSPREY1x0;
-                      break;
-              case 0x0014:
-              case 0x0015:
-                      btv->c.type = BTTV_BOARD_OSPREY1x1;
-                      break;
-              case 0x0016:
-              case 0x0017:
-              case 0x0020:
-                      btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
-                      break;
-              case 0x0018:
-              case 0x0019:
-              case 0x001E:
-              case 0x001F:
-                      btv->c.type = BTTV_BOARD_OSPREY2xx;
-                      break;
-              case 0x001A:
-              case 0x001B:
-                      btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
-                      break;
-              case 0x0040:
-                      btv->c.type = BTTV_BOARD_OSPREY500;
-                      break;
-              case 0x0050:
-              case 0x0056:
-                      btv->c.type = BTTV_BOARD_OSPREY540;
-                      /* bttv_osprey_540_init(btv); */
-                      break;
-              case 0x0060:
-              case 0x0070:
-                      btv->c.type = BTTV_BOARD_OSPREY2x0;
-                      /* enable output on select control lines */
-                      gpio_inout(0xffffff,0x000303);
-                      break;
-              default:
-                      /* unknown...leave generic, but get serial # */
-                      break;
-              }
-              serial =  (ee[offset+6] << 24)
-                      | (ee[offset+7] << 16)
-                      | (ee[offset+8] <<  8)
-                      | (ee[offset+9]);
-       }
-
-       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
-             btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial);
-}
-
-/* ----------------------------------------------------------------------- */
-/* AVermedia specific stuff, from  bktr_card.c                             */
-
-static int tuner_0_table[] = {
-       TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
-       TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
-       TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
-       TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
-       TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
-       TUNER_PHILIPS_FM1216ME_MK3 };
-
-static int tuner_1_table[] = {
-       TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
-       TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
-       TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
-       TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
-       TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
-
-static void __devinit avermedia_eeprom(struct bttv *btv)
-{
-       int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
-
-       tuner_make      = (eeprom_data[0x41] & 0x7);
-       tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
-       tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
-       btv->has_remote = (eeprom_data[0x42] & 0x01);
-
-       if (tuner_make == 0 || tuner_make == 2)
-               if(tuner_format <=0x0a)
-                       tuner = tuner_0_table[tuner_format];
-       if (tuner_make == 1)
-               if(tuner_format <=9)
-                       tuner = tuner_1_table[tuner_format];
-
-       if (tuner_make == 4)
-               if(tuner_format == 0x09)
-                       tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
-
-       printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
-               btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]);
-       if(tuner) {
-               btv->tuner_type=tuner;
-               printk("%d",tuner);
-       } else
-               printk("Unknown type");
-       printk(" radio:%s remote control:%s\n",
-              tuner_tv_fm     ? "yes" : "no",
-              btv->has_remote ? "yes" : "no");
-}
-
-/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */
-void bttv_tda9880_setnorm(struct bttv *btv, int norm)
-{
-       /* fix up our card entry */
-       if(norm==VIDEO_MODE_NTSC) {
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x957fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x957fff;
-               dprintk("bttv_tda9880_setnorm to NTSC\n");
-       }
-       else {
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x947fff;
-               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x947fff;
-               dprintk("bttv_tda9880_setnorm to PAL\n");
-       }
-       /* set GPIO according */
-       gpio_bits(bttv_tvcards[btv->c.type].gpiomask,
-                 bttv_tvcards[btv->c.type].audiomux[btv->audio]);
-}
-
-
-/*
- * reset/enable the MSP on some Hauppauge cards
- * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
- *
- * Hauppauge:  pin  5
- * Voodoo:     pin 20
- */
-static void __devinit boot_msp34xx(struct bttv *btv, int pin)
-{
-       int mask = (1 << pin);
-
-       gpio_inout(mask,mask);
-       gpio_bits(mask,0);
-       udelay(2500);
-       gpio_bits(mask,mask);
-
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"msp34xx");
-       if (bttv_verbose)
-               printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line "
-                      "init [%d]\n", btv->c.nr, pin);
-}
-
-static void __devinit boot_bt832(struct bttv *btv)
-{
-}
-
-/* ----------------------------------------------------------------------- */
-/*  Imagenation L-Model PXC200 Framegrabber */
-/*  This is basically the same procedure as
- *  used by Alessandro Rubini in his pxc200
- *  driver, but using BTTV functions */
-
-static void __devinit init_PXC200(struct bttv *btv)
-{
-       static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
-                                           0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-                                           0x00 };
-       unsigned int i;
-       int tmp;
-       u32 val;
-
-       /* Initialise GPIO-connevted stuff */
-       gpio_inout(0xffffff, (1<<13));
-       gpio_write(0);
-       udelay(3);
-       gpio_write(1<<13);
-       /* GPIO inputs are pulled up, so no need to drive
-        * reset pin any longer */
-       gpio_bits(0xffffff, 0);
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"pxc200");
-
-       /*  we could/should try and reset/control the AD pots? but
-           right now  we simply  turned off the crushing.  Without
-           this the AGC drifts drifts
-           remember the EN is reverse logic -->
-           setting BT848_ADC_AGC_EN disable the AGC
-           tboult@eecs.lehigh.edu
-       */
-
-       btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC);
-
-       /*      Initialise MAX517 DAC */
-       printk(KERN_INFO "Setting DAC reference voltage level ...\n");
-       bttv_I2CWrite(btv,0x5E,0,0x80,1);
-
-       /*      Initialise 12C508 PIC */
-       /*      The I2CWrite and I2CRead commmands are actually to the
-        *      same chips - but the R/W bit is included in the address
-        *      argument so the numbers are different */
-
-
-       printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
-
-       /* First of all, enable the clock line. This is used in the PXC200-F */
-       val = btread(BT848_GPIO_DMA_CTL);
-       val |= BT848_GPIO_DMA_CTL_GPCLKMODE;
-       btwrite(val, BT848_GPIO_DMA_CTL);
-
-       /* Then, push to 0 the reset pin long enough to reset the *
-        * device same as above for the reset line, but not the same
-        * value sent to the GPIO-connected stuff
-        * which one is the good one? */
-       gpio_inout(0xffffff,(1<<2));
-       gpio_write(0);
-       udelay(10);
-       gpio_write(1<<2);
-
-       for (i = 0; i < ARRAY_SIZE(vals); i++) {
-               tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
-               if (tmp != -1) {
-                       printk(KERN_INFO
-                              "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n",
-                              vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL));
-               }
-       }
-
-       printk(KERN_INFO "PXC200 Initialised.\n");
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-/*
- *  The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock
- *  it. This apparently involves the following procedure for each 878 chip:
- *
- *  1) write 0x00C3FEFF to the GPIO_OUT_EN register
- *
- *  2)  write to GPIO_DATA
- *      - 0x0E
- *      - sleep 1ms
- *      - 0x10 + 0x0E
- *      - sleep 10ms
- *      - 0x0E
- *     read from GPIO_DATA into buf (uint_32)
- *      - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 )
- *                 error. ERROR_CPLD_Check_Failed stop.
- *
- *  3) write to GPIO_DATA
- *      - write 0x4400 + 0x0E
- *      - sleep 10ms
- *      - write 0x4410 + 0x0E
- *      - sleep 1ms
- *      - write 0x0E
- *     read from GPIO_DATA into buf (uint_32)
- *      - if ( buf>>18 & 0x01 ) || ( buf>>19 && 0x01 != 0 )
- *                error. ERROR_CPLD_Check_Failed.
- */
-/* ----------------------------------------------------------------------- */
-static void
-init_RTV24 (struct bttv *btv)
-{
-       uint32_t dataRead = 0;
-       long watchdog_value = 0x0E;
-
-       printk (KERN_INFO
-               "bttv%d: Adlink RTV-24 initialisation in progress ...\n",
-               btv->c.nr);
-
-       btwrite (0x00c3feff, BT848_GPIO_OUT_EN);
-
-       btwrite (0 + watchdog_value, BT848_GPIO_DATA);
-       msleep (1);
-       btwrite (0x10 + watchdog_value, BT848_GPIO_DATA);
-       msleep (10);
-       btwrite (0 + watchdog_value, BT848_GPIO_DATA);
-
-       dataRead = btread (BT848_GPIO_DATA);
-
-       if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) {
-               printk (KERN_INFO
-                       "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
-                       btv->c.nr, dataRead);
-       }
-
-       btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA);
-       msleep (10);
-       btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA);
-       msleep (1);
-       btwrite (watchdog_value, BT848_GPIO_DATA);
-       msleep (1);
-       dataRead = btread (BT848_GPIO_DATA);
-
-       if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) {
-               printk (KERN_INFO
-                       "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
-                       btv->c.nr, dataRead);
-
-               return;
-       }
-
-       printk (KERN_INFO
-               "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr);
-}
-
-
-
-/* ----------------------------------------------------------------------- */
-/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports     */
-/*
- * Copyright (c) 1999 Csaba Halasz <qgehali@uni-miskolc.hu>
- * This code is placed under the terms of the GNU General Public License
- *
- * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
- */
-
-static void bus_low(struct bttv *btv, int bit)
-{
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-               udelay(5);
-       }
-
-       gpio_bits(bit,0);
-       udelay(5);
-
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
-               udelay(5);
-       }
-}
-
-static void bus_high(struct bttv *btv, int bit)
-{
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-               udelay(5);
-       }
-
-       gpio_bits(bit,bit);
-       udelay(5);
-
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
-               udelay(5);
-       }
-}
-
-static int bus_in(struct bttv *btv, int bit)
-{
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-               udelay(5);
-
-               gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
-               udelay(5);
-       }
-       return gpio_read() & (bit);
-}
-
-/* TEA5757 register bits */
-#define TEA_FREQ               0:14
-#define TEA_BUFFER             15:15
-
-#define TEA_SIGNAL_STRENGTH    16:17
-
-#define TEA_PORT1              18:18
-#define TEA_PORT0              19:19
-
-#define TEA_BAND               20:21
-#define TEA_BAND_FM            0
-#define TEA_BAND_MW            1
-#define TEA_BAND_LW            2
-#define TEA_BAND_SW            3
-
-#define TEA_MONO               22:22
-#define TEA_ALLOW_STEREO       0
-#define TEA_FORCE_MONO         1
-
-#define TEA_SEARCH_DIRECTION   23:23
-#define TEA_SEARCH_DOWN                0
-#define TEA_SEARCH_UP          1
-
-#define TEA_STATUS             24:24
-#define TEA_STATUS_TUNED       0
-#define TEA_STATUS_SEARCHING   1
-
-/* Low-level stuff */
-static int tea5757_read(struct bttv *btv)
-{
-       unsigned long timeout;
-       int value = 0;
-       int i;
-
-       /* better safe than sorry */
-       gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we);
-
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-               udelay(5);
-       }
-
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"tea5757 read");
-
-       bus_low(btv,btv->mbox_we);
-       bus_low(btv,btv->mbox_clk);
-
-       udelay(10);
-       timeout= jiffies + HZ;
-
-       /* wait for DATA line to go low; error if it doesn't */
-       while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
-               schedule();
-       if (bus_in(btv,btv->mbox_data)) {
-               printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr);
-               return -1;
-       }
-
-       dprintk("bttv%d: tea5757:",btv->c.nr);
-       for(i = 0; i < 24; i++)
-       {
-               udelay(5);
-               bus_high(btv,btv->mbox_clk);
-               udelay(5);
-               dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-');
-               bus_low(btv,btv->mbox_clk);
-               value <<= 1;
-               value |= (bus_in(btv,btv->mbox_data) == 0)?0:1;  /* MSB first */
-               dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M');
-       }
-       dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value);
-       return value;
-}
-
-static int tea5757_write(struct bttv *btv, int value)
-{
-       int i;
-       int reg = value;
-
-       gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data);
-
-       if (btv->mbox_ior) {
-               gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
-                         btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
-               udelay(5);
-       }
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"tea5757 write");
-
-       dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value);
-       bus_low(btv,btv->mbox_clk);
-       bus_high(btv,btv->mbox_we);
-       for(i = 0; i < 25; i++)
-       {
-               if (reg & 0x1000000)
-                       bus_high(btv,btv->mbox_data);
-               else
-                       bus_low(btv,btv->mbox_data);
-               reg <<= 1;
-               bus_high(btv,btv->mbox_clk);
-               udelay(10);
-               bus_low(btv,btv->mbox_clk);
-               udelay(10);
-       }
-       bus_low(btv,btv->mbox_we);  /* unmute !!! */
-       return 0;
-}
-
-void tea5757_set_freq(struct bttv *btv, unsigned short freq)
-{
-       dprintk("tea5757_set_freq %d\n",freq);
-       tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
-}
-
-
-/* ----------------------------------------------------------------------- */
-/* winview                                                                 */
-
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
-       int bits_out, loops, vol, data;
-
-       if (!set) {
-               /* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
-               v->flags |= VIDEO_AUDIO_VOLUME;
-               return;
-       }
-
-       /* 32 levels logarithmic */
-       vol = 32 - ((v->volume>>11));
-       /* units */
-       bits_out = (PT2254_DBS_IN_2>>(vol%5));
-       /* tens */
-       bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-       bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
-       data = gpio_read();
-       data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
-                 WINVIEW_PT2254_STROBE);
-       for (loops = 17; loops >= 0 ; loops--) {
-               if (bits_out & (1<<loops))
-                       data |=  WINVIEW_PT2254_DATA;
-               else
-                       data &= ~WINVIEW_PT2254_DATA;
-               gpio_write(data);
-               udelay(5);
-               data |= WINVIEW_PT2254_CLK;
-               gpio_write(data);
-               udelay(5);
-               data &= ~WINVIEW_PT2254_CLK;
-               gpio_write(data);
-       }
-       data |=  WINVIEW_PT2254_STROBE;
-       data &= ~WINVIEW_PT2254_DATA;
-       gpio_write(data);
-       udelay(10);
-       data &= ~WINVIEW_PT2254_STROBE;
-       gpio_write(data);
-}
-
-/* ----------------------------------------------------------------------- */
-/* mono/stereo control for various cards (which don't use i2c chips but    */
-/* connect something to the GPIO pins                                      */
-
-static void
-gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int con = 0;
-
-       if (set) {
-               gpio_inout(0x300, 0x300);
-               if (v->mode & VIDEO_SOUND_LANG1)
-                       con = 0x000;
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       con = 0x300;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       con = 0x200;
-/*             if (v->mode & VIDEO_SOUND_MONO)
- *                     con = 0x100; */
-               gpio_bits(0x300, con);
-       } else {
-               v->mode = VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-       }
-}
-
-static void
-gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int val, con;
-
-       if (btv->radio_user)
-               return;
-
-       val = gpio_read();
-       if (set) {
-               con = 0x000;
-               if (v->mode & VIDEO_SOUND_LANG2) {
-                       if (v->mode & VIDEO_SOUND_LANG1) {
-                               /* LANG1 + LANG2 */
-                               con = 0x100;
-                       }
-                       else {
-                               /* LANG2 */
-                               con = 0x300;
-                       }
-               }
-               if (con != (val & 0x300)) {
-                       gpio_bits(0x300, con);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"gvbctv5pci");
-               }
-       } else {
-               switch (val & 0x70) {
-                 case 0x10:
-                       v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-                       break;
-                 case 0x30:
-                       v->mode = VIDEO_SOUND_LANG2;
-                       break;
-                 case 0x50:
-                       v->mode = VIDEO_SOUND_LANG1;
-                       break;
-                 case 0x60:
-                       v->mode = VIDEO_SOUND_STEREO;
-                       break;
-                 case 0x70:
-                       v->mode = VIDEO_SOUND_MONO;
-                       break;
-                 default:
-                       v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                                 VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               }
-       }
-}
-
-/*
- * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
- *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
- *  0xdde enables mono and 0xccd enables sap
- *
- * Petr Vandrovec <VANDROVE@vc.cvut.cz>
- *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
- *  input/output sound connection, so both must be set for output mode.
- *
- * Looks like it's needed only for the "tvphone", the "tvphone 98"
- * handles this with a tda9840
- *
- */
-static void
-avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       int val = 0;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-                       val = 0x02;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       val = 0x01;
-               if (val) {
-                       gpio_bits(0x03,val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"avermedia");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1;
-               return;
-       }
-}
-
-static void
-avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       int val = 0;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-                       val = 0x01;
-               if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
-                       val = 0x02;
-               btaor(val, ~0x03, BT848_GPIO_DATA);
-               if (bttv_gpio)
-                       bttv_gpio_tracking(btv,"avermedia");
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               return;
-       }
-}
-
-/* Lifetec 9415 handling */
-static void
-lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       int val = 0;
-
-       if (gpio_read() & 0x4000) {
-               v->mode = VIDEO_SOUND_MONO;
-               return;
-       }
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
-                       val = 0x0080;
-               if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
-                       val = 0x0880;
-               if ((v->mode & VIDEO_SOUND_LANG1) ||
-                   (v->mode & VIDEO_SOUND_MONO))
-                       val = 0;
-               gpio_bits(0x0880, val);
-               if (bttv_gpio)
-                       bttv_gpio_tracking(btv,"lt9415");
-       } else {
-               /* autodetect doesn't work with this card :-( */
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-               return;
-       }
-}
-
-/* TDA9821 on TerraTV+ Bt848, Bt878 */
-static void
-terratv_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int con = 0;
-
-       if (set) {
-               gpio_inout(0x180000,0x180000);
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       con = 0x080000;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       con = 0x180000;
-               gpio_bits(0x180000, con);
-               if (bttv_gpio)
-                       bttv_gpio_tracking(btv,"terratv");
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-static void
-winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned long val = 0;
-
-       if (set) {
-               /*btor (0xc32000, BT848_GPIO_OUT_EN);*/
-               if (v->mode & VIDEO_SOUND_MONO)         /* Mono */
-                       val = 0x420000;
-               if (v->mode & VIDEO_SOUND_LANG1)        /* Mono */
-                       val = 0x420000;
-               if (v->mode & VIDEO_SOUND_LANG2)        /* SAP */
-                       val = 0x410000;
-               if (v->mode & VIDEO_SOUND_STEREO)       /* Stereo */
-                       val = 0x020000;
-               if (val) {
-                       gpio_bits(0x430000, val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"winfast2000");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
- * revision 9B has on-board TDA9874A sound decoder).
- *
- * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
- *       will mute this cards.
- */
-static void
-pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int val = 0;
-
-       if (btv->radio_user)
-               return;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_MONO) {
-                       val = 0x01;
-               }
-               if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-                   || (v->mode & VIDEO_SOUND_STEREO)) {
-                       val = 0x02;
-               }
-               if (val) {
-                       gpio_bits(0x03,val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"pvbt878p9b");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for FlyVideo 2000S (with tda9874 decoder)
- * based on pvbt878p9b_audio() - this is not tested, please fix!!!
- */
-static void
-fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int val = 0xffff;
-
-       if (btv->radio_user)
-               return;
-       if (set) {
-               if (v->mode & VIDEO_SOUND_MONO) {
-                       val = 0x0000;
-               }
-               if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-                   || (v->mode & VIDEO_SOUND_STEREO)) {
-                       val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
-               }
-               if (val != 0xffff) {
-                       gpio_bits(0x1800, val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"fv2000s");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                       VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * sound control for Canopus WinDVR PCI
- * Masaki Suzuki <masaki@btree.org>
- */
-static void
-windvr_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned long val = 0;
-
-       if (set) {
-               if (v->mode & VIDEO_SOUND_MONO)
-                       val = 0x040000;
-               if (v->mode & VIDEO_SOUND_LANG1)
-                       val = 0;
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       val = 0x100000;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       val = 0;
-               if (val) {
-                       gpio_bits(0x140000, val);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv,"windvr");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-       }
-}
-
-/*
- * sound control for AD-TVK503
- * Hiroshi Takekawa <sian@big.or.jp>
- */
-static void
-adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-       unsigned int con = 0xffffff;
-
-       /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
-
-       if (set) {
-               /* btor(***, BT848_GPIO_OUT_EN); */
-               if (v->mode & VIDEO_SOUND_LANG1)
-                       con = 0x00000000;
-               if (v->mode & VIDEO_SOUND_LANG2)
-                       con = 0x00180000;
-               if (v->mode & VIDEO_SOUND_STEREO)
-                       con = 0x00000000;
-               if (v->mode & VIDEO_SOUND_MONO)
-                       con = 0x00060000;
-               if (con != 0xffffff) {
-                       gpio_bits(0x1e0000,con);
-                       if (bttv_gpio)
-                               bttv_gpio_tracking(btv, "adtvk503");
-               }
-       } else {
-               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                         VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-       }
-}
-
-/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
- *
- * This is needed because rv605 don't use a normal multiplex, but a crosspoint
- * switch instead (CD22M3494E). This IC can have multiple active connections
- * between Xn (input) and Yn (output) pins. We need to clear any existing
- * connection prior to establish a new one, pulsing the STROBE pin.
- *
- * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin.
- * GPIO pins are wired as:
- *  GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroler)
- *  GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroler)
- *  GPIO[7]   - DATA (xpoint)    - P1[7] (microcontroler)
- *  GPIO[8]   -                  - P3[5] (microcontroler)
- *  GPIO[9]   - RESET (xpoint)   - P3[6] (microcontroler)
- *  GPIO[10]  - STROBE (xpoint)  - P3[7] (microcontroler)
- *  GPINTR    -                  - P3[4] (microcontroler)
- *
- * The microcontroler is a 80C32 like. It should be possible to change xpoint
- * configuration either directly (as we are doing) or using the microcontroler
- * which is also wired to I2C interface. I have no further info on the
- * microcontroler features, one would need to disassembly the firmware.
- * note: the vendor refused to give any information on this product, all
- *       that stuff was found using a multimeter! :)
- */
-static void rv605_muxsel(struct bttv *btv, unsigned int input)
-{
-       /* reset all conections */
-       gpio_bits(0x200,0x200);
-       mdelay(1);
-       gpio_bits(0x200,0x000);
-       mdelay(1);
-
-       /* create a new conection */
-       gpio_bits(0x480,0x080);
-       gpio_bits(0x480,0x480);
-       mdelay(1);
-       gpio_bits(0x480,0x080);
-       mdelay(1);
-}
-
-/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning]
- *
- * The CS16 (available on eBay cheap) is a PCI board with four Fusion
- * 878A chips, a PCI bridge, an Atmel microcontroller, four sync seperator
- * chips, ten eight input analog multiplexors, a not chip and a few
- * other components.
- *
- * 16 inputs on a secondary bracket are provided and can be selected
- * from each of the four capture chips.  Two of the eight input
- * multiplexors are used to select from any of the 16 input signals.
- *
- * Unsupported hardware capabilities:
- *  . A video output monitor on the secondary bracket can be selected from
- *    one of the 878A chips.
- *  . Another passthrough but I haven't spent any time investigating it.
- *  . Digital I/O (logic level connected to GPIO) is available from an
- *    onboard header.
- *
- * The on chip input mux should always be set to 2.
- * GPIO[16:19] - Video input selection
- * GPIO[0:3]   - Video output monitor select (only available from one 878A)
- * GPIO[?:?]   - Digital I/O.
- *
- * There is an ATMEL microcontroller with an 8031 core on board.  I have not
- * determined what function (if any) it provides.  With the microcontroller
- * and sync seperator chips a guess is that it might have to do with video
- * switching and maybe some digital I/O.
- */
-static void tibetCS16_muxsel(struct bttv *btv, unsigned int input)
-{
-       /* video mux */
-       gpio_bits(0x0f0000, input << 16);
-}
-
-static void tibetCS16_init(struct bttv *btv)
-{
-       /* enable gpio bits, mask obtained via btSpy */
-       gpio_inout(0xffffff, 0x0f7fff);
-       gpio_write(0x0f7fff);
-}
-
-/*
- * The following routines for the Kodicom-4400r get a little mind-twisting.
- * There is a "master" controller and three "slave" controllers, together
- * an analog switch which connects any of 16 cameras to any of the BT87A's.
- * The analog switch is controlled by the "master", but the detection order
- * of the four BT878A chips is in an order which I just don't understand.
- * The "master" is actually the second controller to be detected.  The
- * logic on the board uses logical numbers for the 4 controlers, but
- * those numbers are different from the detection sequence.  When working
- * with the analog switch, we need to "map" from the detection sequence
- * over to the board's logical controller number.  This mapping sequence
- * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
- * unit 3, the second (which is the master) is logical unit 0, etc.
- * We need to maintain the status of the analog switch (which of the 16
- * cameras is connected to which of the 4 controllers).  Rather than
- * add to the bttv structure for this, we use the data reserved for
- * the mbox (unused for this card type).
- */
-
-/*
- * First a routine to set the analog switch, which controls which camera
- * is routed to which controller.  The switch comprises an X-address
- * (gpio bits 0-3, representing the camera, ranging from 0-15), and a
- * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3).
- * A data value (gpio bit 7) of '1' enables the switch, and '0' disables
- * the switch.  A STROBE bit (gpio bit 8) latches the data value into the
- * specified address.  The idea is to set the address and data, then bring
- * STROBE high, and finally bring STROBE back to low.
- */
-static void kodicom4400r_write(struct bttv *btv,
-                              unsigned char xaddr,
-                              unsigned char yaddr,
-                              unsigned char data) {
-       unsigned int udata;
-
-       udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf);
-       gpio_bits(0x1ff, udata);                /* write ADDR and DAT */
-       gpio_bits(0x1ff, udata | (1 << 8));     /* strobe high */
-       gpio_bits(0x1ff, udata);                /* strobe low */
-}
-
-/*
- * Next the mux select.  Both the "master" and "slave" 'cards' (controllers)
- * use this routine.  The routine finds the "master" for the card, maps
- * the controller number from the detected position over to the logical
- * number, writes the appropriate data to the analog switch, and housekeeps
- * the local copy of the switch information.  The parameter 'input' is the
- * requested camera number (0 - 15).
- */
-static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
-{
-       char *sw_status;
-       int xaddr, yaddr;
-       struct bttv *mctlr;
-       static unsigned char map[4] = {3, 0, 2, 1};
-
-       mctlr = master[btv->c.nr];
-       if (mctlr == NULL) {    /* ignore if master not yet detected */
-               return;
-       }
-       yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
-       yaddr = map[yaddr];
-       sw_status = (char *)(&mctlr->mbox_we);
-       xaddr = input & 0xf;
-       /* Check if the controller/camera pair has changed, else ignore */
-       if (sw_status[yaddr] != xaddr)
-       {
-               /* "open" the old switch, "close" the new one, save the new */
-               kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
-               sw_status[yaddr] = xaddr;
-               kodicom4400r_write(mctlr, xaddr, yaddr, 1);
-       }
-}
-
-/*
- * During initialisation, we need to reset the analog switch.  We
- * also preset the switch to map the 4 connectors on the card to the
- * *user's* (see above description of kodicom4400r_muxsel) channels
- * 0 through 3
- */
-static void kodicom4400r_init(struct bttv *btv)
-{
-       char *sw_status = (char *)(&btv->mbox_we);
-       int ix;
-
-       gpio_inout(0x0003ff, 0x0003ff);
-       gpio_write(1 << 9);     /* reset MUX */
-       gpio_write(0);
-       /* Preset camera 0 to the 4 controllers */
-       for (ix=0; ix<4; ix++) {
-               sw_status[ix] = ix;
-               kodicom4400r_write(btv, ix, ix, 1);
-       }
-       /*
-        * Since this is the "master", we need to set up the
-        * other three controller chips' pointers to this structure
-        * for later use in the muxsel routine.
-        */
-       if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3))
-           return;
-       master[btv->c.nr-1] = btv;
-       master[btv->c.nr]   = btv;
-       master[btv->c.nr+1] = btv;
-       master[btv->c.nr+2] = btv;
-}
-
-/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel
- * video multiplexers to provide up to 16 video inputs. These
- * multiplexers are controlled by the lower 8 GPIO pins of the
- * bt878. The multiplexers probably Pericom PI5V331Q or similar.
-
- * xxx0 is pin xxx of multiplexer U5,
- * yyy1 is pin yyy of multiplexer U2
- */
-#define ENA0    0x01
-#define ENB0    0x02
-#define ENA1    0x04
-#define ENB1    0x08
-
-#define IN10    0x10
-#define IN00    0x20
-#define IN11    0x40
-#define IN01    0x80
-
-static void xguard_muxsel(struct bttv *btv, unsigned int input)
-{
-       static const int masks[] = {
-               ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
-               ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
-               ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
-               ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
-       };
-       gpio_write(masks[input%16]);
-}
-static void picolo_tetra_init(struct bttv *btv)
-{
-       /*This is the video input redirection fonctionality : I DID NOT USED IT. */
-       btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */
-       btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A]  set to 1*/
-}
-static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
-{
-
-       dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel =>  input = %d\n",btv->c.nr,input);
-       /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/
-       /*GPIO[20]&GPIO[21] used to choose the right input*/
-       btwrite (input<<20,BT848_GPIO_DATA);
-
-}
-
-/*
- * ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>]
- *
- * The IVC120G security card has 4 i2c controlled TDA8540 matrix
- * swichers to provide 16 channels to MUX0. The TDA8540's have
- * 4 indepedant outputs and as such the IVC120G also has the
- * optional "Monitor Out" bus. This allows the card to be looking
- * at one input while the monitor is looking at another.
- *
- * Since I've couldn't be bothered figuring out how to add an
- * independant muxsel for the monitor bus, I've just set it to
- * whatever the card is looking at.
- *
- *  OUT0 of the TDA8540's is connected to MUX0         (0x03)
- *  OUT1 of the TDA8540's is connected to "Monitor Out"        (0x0C)
- *
- *  TDA8540_ALT3 IN0-3 = Channel 13 - 16       (0x03)
- *  TDA8540_ALT4 IN0-3 = Channel 1 - 4         (0x03)
- *  TDA8540_ALT5 IN0-3 = Channel 5 - 8         (0x03)
- *  TDA8540_ALT6 IN0-3 = Channel 9 - 12                (0x03)
- *
- */
-
-/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */
-#define I2C_TDA8540        0x90
-#define I2C_TDA8540_ALT1   0x92
-#define I2C_TDA8540_ALT2   0x94
-#define I2C_TDA8540_ALT3   0x96
-#define I2C_TDA8540_ALT4   0x98
-#define I2C_TDA8540_ALT5   0x9a
-#define I2C_TDA8540_ALT6   0x9c
-
-static void ivc120_muxsel(struct bttv *btv, unsigned int input)
-{
-       /* Simple maths */
-       int key = input % 4;
-       int matrix = input / 4;
-
-       dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n",
-               btv->c.nr, input, matrix, key);
-
-       /* Handles the input selection on the TDA8540's */
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00,
-                     ((matrix == 3) ? (key | key << 2) : 0x00), 1);
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00,
-                     ((matrix == 0) ? (key | key << 2) : 0x00), 1);
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00,
-                     ((matrix == 1) ? (key | key << 2) : 0x00), 1);
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00,
-                     ((matrix == 2) ? (key | key << 2) : 0x00), 1);
-
-       /* Handles the output enables on the TDA8540's */
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02,
-                     ((matrix == 3) ? 0x03 : 0x00), 1);  /* 13 - 16 */
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02,
-                     ((matrix == 0) ? 0x03 : 0x00), 1);  /* 1-4 */
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02,
-                     ((matrix == 1) ? 0x03 : 0x00), 1);  /* 5-8 */
-       bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02,
-                     ((matrix == 2) ? 0x03 : 0x00), 1);  /* 9-12 */
-
-       /* Selects MUX0 for input on the 878 */
-       btaor((0)<<5, ~(3<<5), BT848_IFORM);
-}
-
-
-/* PXC200 muxsel helper
- * luke@syseng.anu.edu.au
- * another transplant
- * from Alessandro Rubini (rubini@linux.it)
- *
- * There are 4 kinds of cards:
- * PXC200L which is bt848
- * PXC200F which is bt848 with PIC controlling mux
- * PXC200AL which is bt878
- * PXC200AF which is bt878 with PIC controlling mux
- */
-#define PX_CFG_PXC200F 0x01
-#define PX_FLAG_PXC200A  0x00001000 /* a pxc200A is bt-878 based */
-#define PX_I2C_PIC       0x0f
-#define PX_PXC200A_CARDID 0x200a1295
-#define PX_I2C_CMD_CFG   0x00
-
-static void PXC200_muxsel(struct bttv *btv, unsigned int input)
-{
-       int rc;
-       long mux;
-       int bitmask;
-       unsigned char buf[2];
-
-       /* Read PIC config to determine if this is a PXC200F */
-       /* PX_I2C_CMD_CFG*/
-       buf[0]=0;
-       buf[1]=0;
-       rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1);
-       if (rc) {
-         printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc);
-         /* not PXC ? do nothing */
-         return;
-       }
-
-       rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL);
-       if (!(rc & PX_CFG_PXC200F)) {
-         printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc);
-         return;
-       }
-
-
-       /* The multiplexer in the 200F is handled by the GPIO port */
-       /* get correct mapping between inputs  */
-       /*  mux = bttv_tvcards[btv->type].muxsel[input] & 3; */
-       /* ** not needed!?   */
-       mux = input;
-
-       /* make sure output pins are enabled */
-       /* bitmask=0x30f; */
-       bitmask=0x302;
-       /* check whether we have a PXC200A */
-       if (btv->cardid == PX_PXC200A_CARDID)  {
-          bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
-          bitmask |= 7<<4; /* the DAC */
-       }
-       btwrite(bitmask, BT848_GPIO_OUT_EN);
-
-       bitmask = btread(BT848_GPIO_DATA);
-       if (btv->cardid == PX_PXC200A_CARDID)
-         bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
-       else /* older device */
-         bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
-       btwrite(bitmask,BT848_GPIO_DATA);
-
-       /*
-        * Was "to be safe, set the bt848 to input 0"
-        * Actually, since it's ok at load time, better not messing
-        * with these bits (on PXC200AF you need to set mux 2 here)
-        *
-        * needed because bttv-driver sets mux before calling this function
-        */
-       if (btv->cardid == PX_PXC200A_CARDID)
-         btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
-       else /* older device */
-         btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
-
-       printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux);
-}
-
-/* ----------------------------------------------------------------------- */
-/* motherboard chipset specific stuff                                      */
-
-void __devinit bttv_check_chipset(void)
-{
-       int pcipci_fail = 0;
-       struct pci_dev *dev = NULL;
-
-       if (pci_pci_problems & PCIPCI_FAIL)
-               pcipci_fail = 1;
-       if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
-               triton1 = 1;
-       if (pci_pci_problems & PCIPCI_VSFX)
-               vsfx = 1;
-#ifdef PCIPCI_ALIMAGIK
-       if (pci_pci_problems & PCIPCI_ALIMAGIK)
-               latency = 0x0A;
-#endif
-
-
-       /* print warnings about any quirks found */
-       if (triton1)
-               printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
-       if (vsfx)
-               printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
-       if (pcipci_fail) {
-               printk(KERN_INFO "bttv: bttv and your chipset may not work "
-                                                       "together.\n");
-               if (!no_overlay) {
-                       printk(KERN_INFO "bttv: overlay will be disabled.\n");
-                       no_overlay = 1;
-               } else {
-                       printk(KERN_INFO "bttv: overlay forced. Use this "
-                                               "option at your own risk.\n");
-               }
-       }
-       if (UNSET != latency)
-               printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
-       while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                     PCI_DEVICE_ID_INTEL_82441, dev))) {
-               unsigned char b;
-               pci_read_config_byte(dev, 0x53, &b);
-               if (bttv_debug)
-                       printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
-                              "bufcon=0x%02x\n",b);
-       }
-}
-
-int __devinit bttv_handle_chipset(struct bttv *btv)
-{
-       unsigned char command;
-
-       if (!triton1 && !vsfx && UNSET == latency)
-               return 0;
-
-       if (bttv_verbose) {
-               if (triton1)
-                       printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr);
-               if (vsfx && btv->id >= 878)
-                       printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr);
-               if (UNSET != latency)
-                       printk(KERN_INFO "bttv%d: setting pci timer to %d\n",
-                              btv->c.nr,latency);
-       }
-
-       if (btv->id < 878) {
-               /* bt848 (mis)uses a bit in the irq mask for etbf */
-               if (triton1)
-                       btv->triton1 = BT848_INT_ETBF;
-       } else {
-               /* bt878 has a bit in the pci config space for it */
-               pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
-               if (triton1)
-                       command |= BT878_EN_TBFX;
-               if (vsfx)
-                       command |= BT878_EN_VSFX;
-               pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
-       }
-       if (UNSET != latency)
-               pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
-       return 0;
-}
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
deleted file mode 100644 (file)
index c0415d6..0000000
+++ /dev/null
@@ -1,4264 +0,0 @@
-/*
-
-    bttv - Bt848 frame grabber driver
-
-    Copyright (C) 1996,97,98 Ralph  Metzler <rjkm@thp.uni-koeln.de>
-                          & Marcus Metzler <mocm@thp.uni-koeln.de>
-    (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
-
-    some v4l2 code lines are taken from Justin's bttv2 driver which is
-    (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the 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/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kdev_t.h>
-#include "bttvp.h"
-#include <media/v4l2-common.h>
-
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-#include "rds.h"
-
-
-unsigned int bttv_num;                 /* number of Bt848s in use */
-struct bttv bttvs[BTTV_MAX];
-
-unsigned int bttv_debug;
-unsigned int bttv_verbose = 1;
-unsigned int bttv_gpio;
-
-/* config variables */
-#ifdef __BIG_ENDIAN
-static unsigned int bigendian=1;
-#else
-static unsigned int bigendian;
-#endif
-static unsigned int radio[BTTV_MAX];
-static unsigned int irq_debug;
-static unsigned int gbuffers = 8;
-static unsigned int gbufsize = 0x208000;
-
-static int video_nr = -1;
-static int radio_nr = -1;
-static int vbi_nr = -1;
-static int debug_latency;
-
-static unsigned int fdsr;
-
-/* options */
-static unsigned int combfilter;
-static unsigned int lumafilter;
-static unsigned int automute    = 1;
-static unsigned int chroma_agc;
-static unsigned int adc_crush   = 1;
-static unsigned int whitecrush_upper = 0xCF;
-static unsigned int whitecrush_lower = 0x7F;
-static unsigned int vcr_hack;
-static unsigned int irq_iswitch;
-static unsigned int uv_ratio    = 50;
-static unsigned int full_luma_range;
-static unsigned int coring;
-extern int no_overlay;
-
-/* API features (turn on/off stuff for testing) */
-static unsigned int v4l2        = 1;
-
-/* insmod args */
-module_param(bttv_verbose,      int, 0644);
-module_param(bttv_gpio,         int, 0644);
-module_param(bttv_debug,        int, 0644);
-module_param(irq_debug,         int, 0644);
-module_param(debug_latency,     int, 0644);
-
-module_param(fdsr,              int, 0444);
-module_param(video_nr,          int, 0444);
-module_param(radio_nr,          int, 0444);
-module_param(vbi_nr,            int, 0444);
-module_param(gbuffers,          int, 0444);
-module_param(gbufsize,          int, 0444);
-
-module_param(v4l2,              int, 0644);
-module_param(bigendian,         int, 0644);
-module_param(irq_iswitch,       int, 0644);
-module_param(combfilter,        int, 0444);
-module_param(lumafilter,        int, 0444);
-module_param(automute,          int, 0444);
-module_param(chroma_agc,        int, 0444);
-module_param(adc_crush,         int, 0444);
-module_param(whitecrush_upper,  int, 0444);
-module_param(whitecrush_lower,  int, 0444);
-module_param(vcr_hack,          int, 0444);
-module_param(uv_ratio,          int, 0444);
-module_param(full_luma_range,   int, 0444);
-module_param(coring,            int, 0444);
-
-module_param_array(radio, int, NULL, 0444);
-
-MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
-MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
-MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
-MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
-MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
-MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
-MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
-MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
-MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
-MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
-MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
-MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
-MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
-MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
-MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
-MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
-MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
-MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
-
-MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
-MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-/* sysfs                                                                   */
-
-static ssize_t show_card(struct class_device *cd, char *buf)
-{
-       struct video_device *vfd = to_video_device(cd);
-       struct bttv *btv = dev_get_drvdata(vfd->dev);
-       return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
-}
-static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
-
-/* ----------------------------------------------------------------------- */
-/* static data                                                             */
-
-/* special timing tables from conexant... */
-static u8 SRAM_Table[][60] =
-{
-       /* PAL digital input over GPIO[7:0] */
-       {
-               45, // 45 bytes following
-               0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
-               0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
-               0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
-               0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
-               0x37,0x00,0xAF,0x21,0x00
-       },
-       /* NTSC digital input over GPIO[7:0] */
-       {
-               51, // 51 bytes following
-               0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
-               0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
-               0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
-               0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
-               0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
-               0x00,
-       },
-       // TGB_NTSC392 // quartzsight
-       // This table has been modified to be used for Fusion Rev D
-       {
-               0x2A, // size of table = 42
-               0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
-               0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
-               0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
-               0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
-               0x20, 0x00
-       }
-};
-
-const struct bttv_tvnorm bttv_tvnorms[] = {
-       /* PAL-BDGHI */
-       /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
-       /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
-       {
-               .v4l2_id        = V4L2_STD_PAL,
-               .name           = "PAL",
-               .Fsc            = 35468950,
-               .swidth         = 924,
-               .sheight        = 576,
-               .totalwidth     = 1135,
-               .adelay         = 0x7f,
-               .bdelay         = 0x72,
-               .iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-               .scaledtwidth   = 1135,
-               .hdelayx1       = 186,
-               .hactivex1      = 924,
-               .vdelay         = 0x20,
-               .vbipack        = 255,
-               .sram           = 0,
-               /* ITU-R frame line number of the first VBI line
-                  we can capture, of the first and second field. */
-               .vbistart       = { 7,320 },
-       },{
-               .v4l2_id        = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
-               .name           = "NTSC",
-               .Fsc            = 28636363,
-               .swidth         = 768,
-               .sheight        = 480,
-               .totalwidth     = 910,
-               .adelay         = 0x68,
-               .bdelay         = 0x5d,
-               .iform          = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
-               .scaledtwidth   = 910,
-               .hdelayx1       = 128,
-               .hactivex1      = 910,
-               .vdelay         = 0x1a,
-               .vbipack        = 144,
-               .sram           = 1,
-               .vbistart       = { 10, 273 },
-       },{
-               .v4l2_id        = V4L2_STD_SECAM,
-               .name           = "SECAM",
-               .Fsc            = 35468950,
-               .swidth         = 924,
-               .sheight        = 576,
-               .totalwidth     = 1135,
-               .adelay         = 0x7f,
-               .bdelay         = 0xb0,
-               .iform          = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
-               .scaledtwidth   = 1135,
-               .hdelayx1       = 186,
-               .hactivex1      = 922,
-               .vdelay         = 0x20,
-               .vbipack        = 255,
-               .sram           = 0, /* like PAL, correct? */
-               .vbistart       = { 7, 320 },
-       },{
-               .v4l2_id        = V4L2_STD_PAL_Nc,
-               .name           = "PAL-Nc",
-               .Fsc            = 28636363,
-               .swidth         = 640,
-               .sheight        = 576,
-               .totalwidth     = 910,
-               .adelay         = 0x68,
-               .bdelay         = 0x5d,
-               .iform          = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
-               .scaledtwidth   = 780,
-               .hdelayx1       = 130,
-               .hactivex1      = 734,
-               .vdelay         = 0x1a,
-               .vbipack        = 144,
-               .sram           = -1,
-               .vbistart       = { 7, 320 },
-       },{
-               .v4l2_id        = V4L2_STD_PAL_M,
-               .name           = "PAL-M",
-               .Fsc            = 28636363,
-               .swidth         = 640,
-               .sheight        = 480,
-               .totalwidth     = 910,
-               .adelay         = 0x68,
-               .bdelay         = 0x5d,
-               .iform          = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
-               .scaledtwidth   = 780,
-               .hdelayx1       = 135,
-               .hactivex1      = 754,
-               .vdelay         = 0x1a,
-               .vbipack        = 144,
-               .sram           = -1,
-               .vbistart       = { 10, 273 },
-       },{
-               .v4l2_id        = V4L2_STD_PAL_N,
-               .name           = "PAL-N",
-               .Fsc            = 35468950,
-               .swidth         = 768,
-               .sheight        = 576,
-               .totalwidth     = 1135,
-               .adelay         = 0x7f,
-               .bdelay         = 0x72,
-               .iform          = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
-               .scaledtwidth   = 944,
-               .hdelayx1       = 186,
-               .hactivex1      = 922,
-               .vdelay         = 0x20,
-               .vbipack        = 144,
-               .sram           = -1,
-               .vbistart       = { 7, 320},
-       },{
-               .v4l2_id        = V4L2_STD_NTSC_M_JP,
-               .name           = "NTSC-JP",
-               .Fsc            = 28636363,
-               .swidth         = 640,
-               .sheight        = 480,
-               .totalwidth     = 910,
-               .adelay         = 0x68,
-               .bdelay         = 0x5d,
-               .iform          = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
-               .scaledtwidth   = 780,
-               .hdelayx1       = 135,
-               .hactivex1      = 754,
-               .vdelay         = 0x16,
-               .vbipack        = 144,
-               .sram           = -1,
-               .vbistart       = {10, 273},
-       },{
-               /* that one hopefully works with the strange timing
-                * which video recorders produce when playing a NTSC
-                * tape on a PAL TV ... */
-               .v4l2_id        = V4L2_STD_PAL_60,
-               .name           = "PAL-60",
-               .Fsc            = 35468950,
-               .swidth         = 924,
-               .sheight        = 480,
-               .totalwidth     = 1135,
-               .adelay         = 0x7f,
-               .bdelay         = 0x72,
-               .iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-               .scaledtwidth   = 1135,
-               .hdelayx1       = 186,
-               .hactivex1      = 924,
-               .vdelay         = 0x1a,
-               .vbipack        = 255,
-               .vtotal         = 524,
-               .sram           = -1,
-               .vbistart       = { 10, 273 },
-       }
-};
-static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
-
-/* ----------------------------------------------------------------------- */
-/* bttv format list
-   packed pixel formats must come first */
-static const struct bttv_format bttv_formats[] = {
-       {
-               .name     = "8 bpp, gray",
-               .palette  = VIDEO_PALETTE_GREY,
-               .fourcc   = V4L2_PIX_FMT_GREY,
-               .btformat = BT848_COLOR_FMT_Y8,
-               .depth    = 8,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "8 bpp, dithered color",
-               .palette  = VIDEO_PALETTE_HI240,
-               .fourcc   = V4L2_PIX_FMT_HI240,
-               .btformat = BT848_COLOR_FMT_RGB8,
-               .depth    = 8,
-               .flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
-       },{
-               .name     = "15 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB555,
-               .fourcc   = V4L2_PIX_FMT_RGB555,
-               .btformat = BT848_COLOR_FMT_RGB15,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "15 bpp RGB, be",
-               .palette  = -1,
-               .fourcc   = V4L2_PIX_FMT_RGB555X,
-               .btformat = BT848_COLOR_FMT_RGB15,
-               .btswap   = 0x03, /* byteswap */
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "16 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB565,
-               .fourcc   = V4L2_PIX_FMT_RGB565,
-               .btformat = BT848_COLOR_FMT_RGB16,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "16 bpp RGB, be",
-               .palette  = -1,
-               .fourcc   = V4L2_PIX_FMT_RGB565X,
-               .btformat = BT848_COLOR_FMT_RGB16,
-               .btswap   = 0x03, /* byteswap */
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "24 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB24,
-               .fourcc   = V4L2_PIX_FMT_BGR24,
-               .btformat = BT848_COLOR_FMT_RGB24,
-               .depth    = 24,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "32 bpp RGB, le",
-               .palette  = VIDEO_PALETTE_RGB32,
-               .fourcc   = V4L2_PIX_FMT_BGR32,
-               .btformat = BT848_COLOR_FMT_RGB32,
-               .depth    = 32,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "32 bpp RGB, be",
-               .palette  = -1,
-               .fourcc   = V4L2_PIX_FMT_RGB32,
-               .btformat = BT848_COLOR_FMT_RGB32,
-               .btswap   = 0x0f, /* byte+word swap */
-               .depth    = 32,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "4:2:2, packed, YUYV",
-               .palette  = VIDEO_PALETTE_YUV422,
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .btformat = BT848_COLOR_FMT_YUY2,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "4:2:2, packed, YUYV",
-               .palette  = VIDEO_PALETTE_YUYV,
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .btformat = BT848_COLOR_FMT_YUY2,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "4:2:2, packed, UYVY",
-               .palette  = VIDEO_PALETTE_UYVY,
-               .fourcc   = V4L2_PIX_FMT_UYVY,
-               .btformat = BT848_COLOR_FMT_YUY2,
-               .btswap   = 0x03, /* byteswap */
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "4:2:2, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV422P,
-               .fourcc   = V4L2_PIX_FMT_YUV422P,
-               .btformat = BT848_COLOR_FMT_YCrCb422,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PLANAR,
-               .hshift   = 1,
-               .vshift   = 0,
-       },{
-               .name     = "4:2:0, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV420P,
-               .fourcc   = V4L2_PIX_FMT_YUV420,
-               .btformat = BT848_COLOR_FMT_YCrCb422,
-               .depth    = 12,
-               .flags    = FORMAT_FLAGS_PLANAR,
-               .hshift   = 1,
-               .vshift   = 1,
-       },{
-               .name     = "4:2:0, planar, Y-Cr-Cb",
-               .palette  = -1,
-               .fourcc   = V4L2_PIX_FMT_YVU420,
-               .btformat = BT848_COLOR_FMT_YCrCb422,
-               .depth    = 12,
-               .flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
-               .hshift   = 1,
-               .vshift   = 1,
-       },{
-               .name     = "4:1:1, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV411P,
-               .fourcc   = V4L2_PIX_FMT_YUV411P,
-               .btformat = BT848_COLOR_FMT_YCrCb411,
-               .depth    = 12,
-               .flags    = FORMAT_FLAGS_PLANAR,
-               .hshift   = 2,
-               .vshift   = 0,
-       },{
-               .name     = "4:1:0, planar, Y-Cb-Cr",
-               .palette  = VIDEO_PALETTE_YUV410P,
-               .fourcc   = V4L2_PIX_FMT_YUV410,
-               .btformat = BT848_COLOR_FMT_YCrCb411,
-               .depth    = 9,
-               .flags    = FORMAT_FLAGS_PLANAR,
-               .hshift   = 2,
-               .vshift   = 2,
-       },{
-               .name     = "4:1:0, planar, Y-Cr-Cb",
-               .palette  = -1,
-               .fourcc   = V4L2_PIX_FMT_YVU410,
-               .btformat = BT848_COLOR_FMT_YCrCb411,
-               .depth    = 9,
-               .flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
-               .hshift   = 2,
-               .vshift   = 2,
-       },{
-               .name     = "raw scanlines",
-               .palette  = VIDEO_PALETTE_RAW,
-               .fourcc   = -1,
-               .btformat = BT848_COLOR_FMT_RAW,
-               .depth    = 8,
-               .flags    = FORMAT_FLAGS_RAW,
-       }
-};
-static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
-
-/* ----------------------------------------------------------------------- */
-
-#define V4L2_CID_PRIVATE_CHROMA_AGC  (V4L2_CID_PRIVATE_BASE + 0)
-#define V4L2_CID_PRIVATE_COMBFILTER  (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_LUMAFILTER  (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_PRIVATE_AGC_CRUSH   (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_PRIVATE_VCR_HACK    (V4L2_CID_PRIVATE_BASE + 5)
-#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER   (V4L2_CID_PRIVATE_BASE + 6)
-#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER   (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_UV_RATIO    (V4L2_CID_PRIVATE_BASE + 8)
-#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE    (V4L2_CID_PRIVATE_BASE + 9)
-#define V4L2_CID_PRIVATE_CORING      (V4L2_CID_PRIVATE_BASE + 10)
-#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 11)
-
-static const struct v4l2_queryctrl no_ctl = {
-       .name  = "42",
-       .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-static const struct v4l2_queryctrl bttv_ctls[] = {
-       /* --- video --- */
-       {
-               .id            = V4L2_CID_BRIGHTNESS,
-               .name          = "Brightness",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 256,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_CONTRAST,
-               .name          = "Contrast",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 128,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_SATURATION,
-               .name          = "Saturation",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 128,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_HUE,
-               .name          = "Hue",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 256,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },
-       /* --- audio --- */
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 65535,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_AUDIO_BALANCE,
-               .name          = "Balance",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_AUDIO_BASS,
-               .name          = "Bass",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_AUDIO_TREBLE,
-               .name          = "Treble",
-               .minimum       = 0,
-               .maximum       = 65535,
-               .step          = 65535/100,
-               .default_value = 32768,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },
-       /* --- private --- */
-       {
-               .id            = V4L2_CID_PRIVATE_CHROMA_AGC,
-               .name          = "chroma agc",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_COMBFILTER,
-               .name          = "combfilter",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_AUTOMUTE,
-               .name          = "automute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_LUMAFILTER,
-               .name          = "luma decimation filter",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_AGC_CRUSH,
-               .name          = "agc crush",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_VCR_HACK,
-               .name          = "vcr hack",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
-               .name          = "whitecrush upper",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 0xCF,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
-               .name          = "whitecrush lower",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 0x7F,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_PRIVATE_UV_RATIO,
-               .name          = "uv ratio",
-               .minimum       = 0,
-               .maximum       = 100,
-               .step          = 1,
-               .default_value = 50,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
-               .name          = "full luma range",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_CORING,
-               .name          = "coring",
-               .minimum       = 0,
-               .maximum       = 3,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-
-
-
-};
-static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
-
-/* ----------------------------------------------------------------------- */
-/* resource management                                                     */
-
-static
-int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
-{
-       if (fh->resources & bit)
-               /* have it already allocated */
-               return 1;
-
-       /* is it free? */
-       mutex_lock(&btv->reslock);
-       if (btv->resources & bit) {
-               /* no, someone else uses it */
-               mutex_unlock(&btv->reslock);
-               return 0;
-       }
-       /* it's free, grab it */
-       fh->resources  |= bit;
-       btv->resources |= bit;
-       mutex_unlock(&btv->reslock);
-       return 1;
-}
-
-static
-int check_btres(struct bttv_fh *fh, int bit)
-{
-       return (fh->resources & bit);
-}
-
-static
-int locked_btres(struct bttv *btv, int bit)
-{
-       return (btv->resources & bit);
-}
-
-static
-void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
-{
-       if ((fh->resources & bits) != bits) {
-               /* trying to free ressources not allocated by us ... */
-               printk("bttv: BUG! (btres)\n");
-       }
-       mutex_lock(&btv->reslock);
-       fh->resources  &= ~bits;
-       btv->resources &= ~bits;
-       mutex_unlock(&btv->reslock);
-}
-
-/* ----------------------------------------------------------------------- */
-/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC          */
-
-/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
-   PLL_X = Reference pre-divider (0=1, 1=2)
-   PLL_C = Post divider (0=6, 1=4)
-   PLL_I = Integer input
-   PLL_F = Fractional input
-
-   F_input = 28.636363 MHz:
-   PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
-*/
-
-static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
-{
-       unsigned char fl, fh, fi;
-
-       /* prevent overflows */
-       fin/=4;
-       fout/=4;
-
-       fout*=12;
-       fi=fout/fin;
-
-       fout=(fout%fin)*256;
-       fh=fout/fin;
-
-       fout=(fout%fin)*256;
-       fl=fout/fin;
-
-       btwrite(fl, BT848_PLL_F_LO);
-       btwrite(fh, BT848_PLL_F_HI);
-       btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
-}
-
-static void set_pll(struct bttv *btv)
-{
-       int i;
-
-       if (!btv->pll.pll_crystal)
-               return;
-
-       if (btv->pll.pll_ofreq == btv->pll.pll_current) {
-               dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
-               return;
-       }
-
-       if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
-               /* no PLL needed */
-               if (btv->pll.pll_current == 0)
-                       return;
-               bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
-                       btv->c.nr,btv->pll.pll_ifreq);
-               btwrite(0x00,BT848_TGCTRL);
-               btwrite(0x00,BT848_PLL_XCI);
-               btv->pll.pll_current = 0;
-               return;
-       }
-
-       bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
-               btv->pll.pll_ifreq, btv->pll.pll_ofreq);
-       set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
-
-       for (i=0; i<10; i++) {
-               /*  Let other people run while the PLL stabilizes */
-               bttv_printk(".");
-               msleep(10);
-
-               if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
-                       btwrite(0,BT848_DSTATUS);
-               } else {
-                       btwrite(0x08,BT848_TGCTRL);
-                       btv->pll.pll_current = btv->pll.pll_ofreq;
-                       bttv_printk(" ok\n");
-                       return;
-               }
-       }
-       btv->pll.pll_current = -1;
-       bttv_printk("failed\n");
-       return;
-}
-
-/* used to switch between the bt848's analog/digital video capture modes */
-static void bt848A_set_timing(struct bttv *btv)
-{
-       int i, len;
-       int table_idx = bttv_tvnorms[btv->tvnorm].sram;
-       int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;
-
-       if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
-               dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
-                       btv->c.nr,table_idx);
-
-               /* timing change...reset timing generator address */
-               btwrite(0x00, BT848_TGCTRL);
-               btwrite(0x02, BT848_TGCTRL);
-               btwrite(0x00, BT848_TGCTRL);
-
-               len=SRAM_Table[table_idx][0];
-               for(i = 1; i <= len; i++)
-                       btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
-               btv->pll.pll_ofreq = 27000000;
-
-               set_pll(btv);
-               btwrite(0x11, BT848_TGCTRL);
-               btwrite(0x41, BT848_DVSIF);
-       } else {
-               btv->pll.pll_ofreq = fsc;
-               set_pll(btv);
-               btwrite(0x0, BT848_DVSIF);
-       }
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void bt848_bright(struct bttv *btv, int bright)
-{
-       int value;
-
-       // printk("bttv: set bright: %d\n",bright); // DEBUG
-       btv->bright = bright;
-
-       /* We want -128 to 127 we get 0-65535 */
-       value = (bright >> 8) - 128;
-       btwrite(value & 0xff, BT848_BRIGHT);
-}
-
-static void bt848_hue(struct bttv *btv, int hue)
-{
-       int value;
-
-       btv->hue = hue;
-
-       /* -128 to 127 */
-       value = (hue >> 8) - 128;
-       btwrite(value & 0xff, BT848_HUE);
-}
-
-static void bt848_contrast(struct bttv *btv, int cont)
-{
-       int value,hibit;
-
-       btv->contrast = cont;
-
-       /* 0-511 */
-       value = (cont  >> 7);
-       hibit = (value >> 6) & 4;
-       btwrite(value & 0xff, BT848_CONTRAST_LO);
-       btaor(hibit, ~4, BT848_E_CONTROL);
-       btaor(hibit, ~4, BT848_O_CONTROL);
-}
-
-static void bt848_sat(struct bttv *btv, int color)
-{
-       int val_u,val_v,hibits;
-
-       btv->saturation = color;
-
-       /* 0-511 for the color */
-       val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
-       val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
-       hibits  = (val_u >> 7) & 2;
-       hibits |= (val_v >> 8) & 1;
-       btwrite(val_u & 0xff, BT848_SAT_U_LO);
-       btwrite(val_v & 0xff, BT848_SAT_V_LO);
-       btaor(hibits, ~3, BT848_E_CONTROL);
-       btaor(hibits, ~3, BT848_O_CONTROL);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int
-video_mux(struct bttv *btv, unsigned int input)
-{
-       int mux,mask2;
-
-       if (input >= bttv_tvcards[btv->c.type].video_inputs)
-               return -EINVAL;
-
-       /* needed by RemoteVideo MX */
-       mask2 = bttv_tvcards[btv->c.type].gpiomask2;
-       if (mask2)
-               gpio_inout(mask2,mask2);
-
-       if (input == btv->svhs)  {
-               btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
-               btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
-       } else {
-               btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
-               btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
-       }
-       mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
-       btaor(mux<<5, ~(3<<5), BT848_IFORM);
-       dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
-               btv->c.nr,input,mux);
-
-       /* card specific hook */
-       if(bttv_tvcards[btv->c.type].muxsel_hook)
-               bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
-       return 0;
-}
-
-static char *audio_modes[] = {
-       "audio: tuner", "audio: radio", "audio: extern",
-       "audio: intern", "audio: off"
-};
-
-static int
-audio_mux(struct bttv *btv, int mode)
-{
-       int val,mux,i2c_mux,signal;
-
-       gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
-                  bttv_tvcards[btv->c.type].gpiomask);
-       signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
-
-       switch (mode) {
-       case AUDIO_MUTE:
-               btv->audio |= AUDIO_MUTE;
-               break;
-       case AUDIO_UNMUTE:
-               btv->audio &= ~AUDIO_MUTE;
-               break;
-       case AUDIO_TUNER:
-       case AUDIO_RADIO:
-       case AUDIO_EXTERN:
-       case AUDIO_INTERN:
-               btv->audio &= AUDIO_MUTE;
-               btv->audio |= mode;
-       }
-       i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
-       if (btv->opt_automute && !signal && !btv->radio_user)
-               mux = AUDIO_OFF;
-
-       val = bttv_tvcards[btv->c.type].audiomux[mux];
-       gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,audio_modes[mux]);
-       if (!in_interrupt())
-               bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
-       return 0;
-}
-
-static void
-i2c_vidiocschan(struct bttv *btv)
-{
-       struct video_channel c;
-
-       memset(&c,0,sizeof(c));
-       c.norm    = btv->tvnorm;
-       c.channel = btv->input;
-       bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
-       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
-               bttv_tda9880_setnorm(btv,c.norm);
-}
-
-static int
-set_tvnorm(struct bttv *btv, unsigned int norm)
-{
-       const struct bttv_tvnorm *tvnorm;
-
-       if (norm < 0 || norm >= BTTV_TVNORMS)
-               return -EINVAL;
-
-       btv->tvnorm = norm;
-       tvnorm = &bttv_tvnorms[norm];
-
-       btwrite(tvnorm->adelay, BT848_ADELAY);
-       btwrite(tvnorm->bdelay, BT848_BDELAY);
-       btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
-             BT848_IFORM);
-       btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
-       btwrite(1, BT848_VBI_PACK_DEL);
-       bt848A_set_timing(btv);
-
-       switch (btv->c.type) {
-       case BTTV_BOARD_VOODOOTV_FM:
-               bttv_tda9880_setnorm(btv,norm);
-               break;
-       }
-       return 0;
-}
-
-static void
-set_input(struct bttv *btv, unsigned int input)
-{
-       unsigned long flags;
-
-       btv->input = input;
-       if (irq_iswitch) {
-               spin_lock_irqsave(&btv->s_lock,flags);
-               if (btv->curr.frame_irq) {
-                       /* active capture -> delayed input switch */
-                       btv->new_input = input;
-               } else {
-                       video_mux(btv,input);
-               }
-               spin_unlock_irqrestore(&btv->s_lock,flags);
-       } else {
-               video_mux(btv,input);
-       }
-       audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ?
-                      AUDIO_TUNER : AUDIO_EXTERN));
-       set_tvnorm(btv,btv->tvnorm);
-       i2c_vidiocschan(btv);
-}
-
-static void init_irqreg(struct bttv *btv)
-{
-       /* clear status */
-       btwrite(0xfffffUL, BT848_INT_STAT);
-
-       if (bttv_tvcards[btv->c.type].no_video) {
-               /* i2c only */
-               btwrite(BT848_INT_I2CDONE,
-                       BT848_INT_MASK);
-       } else {
-               /* full video */
-               btwrite((btv->triton1)  |
-                       (btv->gpioirq ? BT848_INT_GPINT : 0) |
-                       BT848_INT_SCERR |
-                       (fdsr ? BT848_INT_FDSR : 0) |
-                       BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
-                       BT848_INT_FMTCHG|BT848_INT_HLOCK|
-                       BT848_INT_I2CDONE,
-                       BT848_INT_MASK);
-       }
-}
-
-static void init_bt848(struct bttv *btv)
-{
-       int val;
-
-       if (bttv_tvcards[btv->c.type].no_video) {
-               /* very basic init only */
-               init_irqreg(btv);
-               return;
-       }
-
-       btwrite(0x00, BT848_CAP_CTL);
-       btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
-       btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
-
-       /* set planar and packed mode trigger points and         */
-       /* set rising edge of inverted GPINTR pin as irq trigger */
-       btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
-               BT848_GPIO_DMA_CTL_PLTP1_16|
-               BT848_GPIO_DMA_CTL_PLTP23_16|
-               BT848_GPIO_DMA_CTL_GPINTC|
-               BT848_GPIO_DMA_CTL_GPINTI,
-               BT848_GPIO_DMA_CTL);
-
-       val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
-       btwrite(val, BT848_E_SCLOOP);
-       btwrite(val, BT848_O_SCLOOP);
-
-       btwrite(0x20, BT848_E_VSCALE_HI);
-       btwrite(0x20, BT848_O_VSCALE_HI);
-       btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
-               BT848_ADC);
-
-       btwrite(whitecrush_upper, BT848_WC_UP);
-       btwrite(whitecrush_lower, BT848_WC_DOWN);
-
-       if (btv->opt_lumafilter) {
-               btwrite(0, BT848_E_CONTROL);
-               btwrite(0, BT848_O_CONTROL);
-       } else {
-               btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
-               btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
-       }
-
-       bt848_bright(btv,   btv->bright);
-       bt848_hue(btv,      btv->hue);
-       bt848_contrast(btv, btv->contrast);
-       bt848_sat(btv,      btv->saturation);
-
-       /* interrupt */
-       init_irqreg(btv);
-}
-
-static void bttv_reinit_bt848(struct bttv *btv)
-{
-       unsigned long flags;
-
-       if (bttv_verbose)
-               printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
-       spin_lock_irqsave(&btv->s_lock,flags);
-       btv->errors=0;
-       bttv_set_dma(btv,0);
-       spin_unlock_irqrestore(&btv->s_lock,flags);
-
-       init_bt848(btv);
-       btv->pll.pll_current = -1;
-       set_input(btv,btv->input);
-}
-
-static int get_control(struct bttv *btv, struct v4l2_control *c)
-{
-       struct video_audio va;
-       int i;
-
-       for (i = 0; i < BTTV_CTLS; i++)
-               if (bttv_ctls[i].id == c->id)
-                       break;
-       if (i == BTTV_CTLS)
-               return -EINVAL;
-       if (i >= 4 && i <= 8) {
-               memset(&va,0,sizeof(va));
-               bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,&va,0);
-       }
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->value = btv->bright;
-               break;
-       case V4L2_CID_HUE:
-               c->value = btv->hue;
-               break;
-       case V4L2_CID_CONTRAST:
-               c->value = btv->contrast;
-               break;
-       case V4L2_CID_SATURATION:
-               c->value = btv->saturation;
-               break;
-
-       case V4L2_CID_AUDIO_MUTE:
-               c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
-               break;
-       case V4L2_CID_AUDIO_VOLUME:
-               c->value = va.volume;
-               break;
-       case V4L2_CID_AUDIO_BALANCE:
-               c->value = va.balance;
-               break;
-       case V4L2_CID_AUDIO_BASS:
-               c->value = va.bass;
-               break;
-       case V4L2_CID_AUDIO_TREBLE:
-               c->value = va.treble;
-               break;
-
-       case V4L2_CID_PRIVATE_CHROMA_AGC:
-               c->value = btv->opt_chroma_agc;
-               break;
-       case V4L2_CID_PRIVATE_COMBFILTER:
-               c->value = btv->opt_combfilter;
-               break;
-       case V4L2_CID_PRIVATE_LUMAFILTER:
-               c->value = btv->opt_lumafilter;
-               break;
-       case V4L2_CID_PRIVATE_AUTOMUTE:
-               c->value = btv->opt_automute;
-               break;
-       case V4L2_CID_PRIVATE_AGC_CRUSH:
-               c->value = btv->opt_adc_crush;
-               break;
-       case V4L2_CID_PRIVATE_VCR_HACK:
-               c->value = btv->opt_vcr_hack;
-               break;
-       case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
-               c->value = btv->opt_whitecrush_upper;
-               break;
-       case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
-               c->value = btv->opt_whitecrush_lower;
-               break;
-       case V4L2_CID_PRIVATE_UV_RATIO:
-               c->value = btv->opt_uv_ratio;
-               break;
-       case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
-               c->value = btv->opt_full_luma_range;
-               break;
-       case V4L2_CID_PRIVATE_CORING:
-               c->value = btv->opt_coring;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int set_control(struct bttv *btv, struct v4l2_control *c)
-{
-       struct video_audio va;
-       int i,val;
-
-       for (i = 0; i < BTTV_CTLS; i++)
-               if (bttv_ctls[i].id == c->id)
-                       break;
-       if (i == BTTV_CTLS)
-               return -EINVAL;
-       if (i >= 4 && i <= 8) {
-               memset(&va,0,sizeof(va));
-               bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,&va,0);
-       }
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               bt848_bright(btv,c->value);
-               break;
-       case V4L2_CID_HUE:
-               bt848_hue(btv,c->value);
-               break;
-       case V4L2_CID_CONTRAST:
-               bt848_contrast(btv,c->value);
-               break;
-       case V4L2_CID_SATURATION:
-               bt848_sat(btv,c->value);
-               break;
-       case V4L2_CID_AUDIO_MUTE:
-               if (c->value) {
-                       va.flags |= VIDEO_AUDIO_MUTE;
-                       audio_mux(btv, AUDIO_MUTE);
-               } else {
-                       va.flags &= ~VIDEO_AUDIO_MUTE;
-                       audio_mux(btv, AUDIO_UNMUTE);
-               }
-               break;
-
-       case V4L2_CID_AUDIO_VOLUME:
-               va.volume = c->value;
-               break;
-       case V4L2_CID_AUDIO_BALANCE:
-               va.balance = c->value;
-               break;
-       case V4L2_CID_AUDIO_BASS:
-               va.bass = c->value;
-               break;
-       case V4L2_CID_AUDIO_TREBLE:
-               va.treble = c->value;
-               break;
-
-       case V4L2_CID_PRIVATE_CHROMA_AGC:
-               btv->opt_chroma_agc = c->value;
-               val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
-               btwrite(val, BT848_E_SCLOOP);
-               btwrite(val, BT848_O_SCLOOP);
-               break;
-       case V4L2_CID_PRIVATE_COMBFILTER:
-               btv->opt_combfilter = c->value;
-               break;
-       case V4L2_CID_PRIVATE_LUMAFILTER:
-               btv->opt_lumafilter = c->value;
-               if (btv->opt_lumafilter) {
-                       btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
-                       btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
-               } else {
-                       btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
-                       btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
-               }
-               break;
-       case V4L2_CID_PRIVATE_AUTOMUTE:
-               btv->opt_automute = c->value;
-               break;
-       case V4L2_CID_PRIVATE_AGC_CRUSH:
-               btv->opt_adc_crush = c->value;
-               btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
-                       BT848_ADC);
-               break;
-       case V4L2_CID_PRIVATE_VCR_HACK:
-               btv->opt_vcr_hack = c->value;
-               break;
-       case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
-               btv->opt_whitecrush_upper = c->value;
-               btwrite(c->value, BT848_WC_UP);
-               break;
-       case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
-               btv->opt_whitecrush_lower = c->value;
-               btwrite(c->value, BT848_WC_DOWN);
-               break;
-       case V4L2_CID_PRIVATE_UV_RATIO:
-               btv->opt_uv_ratio = c->value;
-               bt848_sat(btv, btv->saturation);
-               break;
-       case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
-               btv->opt_full_luma_range = c->value;
-               btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
-               break;
-       case V4L2_CID_PRIVATE_CORING:
-               btv->opt_coring = c->value;
-               btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (i >= 4 && i <= 8) {
-               bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,&va,1);
-       }
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-void bttv_gpio_tracking(struct bttv *btv, char *comment)
-{
-       unsigned int outbits, data;
-       outbits = btread(BT848_GPIO_OUT_EN);
-       data    = btread(BT848_GPIO_DATA);
-       printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
-              btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
-}
-
-static void bttv_field_count(struct bttv *btv)
-{
-       int need_count = 0;
-
-       if (btv->users)
-               need_count++;
-
-       if (need_count) {
-               /* start field counter */
-               btor(BT848_INT_VSYNC,BT848_INT_MASK);
-       } else {
-               /* stop field counter */
-               btand(~BT848_INT_VSYNC,BT848_INT_MASK);
-               btv->field_count = 0;
-       }
-}
-
-static const struct bttv_format*
-format_by_palette(int palette)
-{
-       unsigned int i;
-
-       for (i = 0; i < BTTV_FORMATS; i++) {
-               if (-1 == bttv_formats[i].palette)
-                       continue;
-               if (bttv_formats[i].palette == palette)
-                       return bttv_formats+i;
-       }
-       return NULL;
-}
-
-static const struct bttv_format*
-format_by_fourcc(int fourcc)
-{
-       unsigned int i;
-
-       for (i = 0; i < BTTV_FORMATS; i++) {
-               if (-1 == bttv_formats[i].fourcc)
-                       continue;
-               if (bttv_formats[i].fourcc == fourcc)
-                       return bttv_formats+i;
-       }
-       return NULL;
-}
-
-/* ----------------------------------------------------------------------- */
-/* misc helpers                                                            */
-
-static int
-bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
-                   struct bttv_buffer *new)
-{
-       struct bttv_buffer *old;
-       unsigned long flags;
-       int retval = 0;
-
-       dprintk("switch_overlay: enter [new=%p]\n",new);
-       if (new)
-               new->vb.state = STATE_DONE;
-       spin_lock_irqsave(&btv->s_lock,flags);
-       old = btv->screen;
-       btv->screen = new;
-       btv->loop_irq |= 1;
-       bttv_set_dma(btv, 0x03);
-       spin_unlock_irqrestore(&btv->s_lock,flags);
-       if (NULL == new)
-               free_btres(btv,fh,RESOURCE_OVERLAY);
-       if (NULL != old) {
-               dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
-               bttv_dma_free(btv, old);
-               kfree(old);
-       }
-       dprintk("switch_overlay: done\n");
-       return retval;
-}
-
-/* ----------------------------------------------------------------------- */
-/* video4linux (1) interface                                               */
-
-static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
-                              const struct bttv_format *fmt,
-                              unsigned int width, unsigned int height,
-                              enum v4l2_field field)
-{
-       int redo_dma_risc = 0;
-       int rc;
-
-       /* check settings */
-       if (NULL == fmt)
-               return -EINVAL;
-       if (fmt->btformat == BT848_COLOR_FMT_RAW) {
-               width  = RAW_BPL;
-               height = RAW_LINES*2;
-               if (width*height > buf->vb.bsize)
-                       return -EINVAL;
-               buf->vb.size = buf->vb.bsize;
-       } else {
-               if (width  < 48 ||
-                   height < 32 ||
-                   width  > bttv_tvnorms[btv->tvnorm].swidth ||
-                   height > bttv_tvnorms[btv->tvnorm].sheight)
-                       return -EINVAL;
-               buf->vb.size = (width * height * fmt->depth) >> 3;
-               if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-                       return -EINVAL;
-       }
-
-       /* alloc + fill struct bttv_buffer (if changed) */
-       if (buf->vb.width != width || buf->vb.height != height ||
-           buf->vb.field != field ||
-           buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
-               buf->vb.width  = width;
-               buf->vb.height = height;
-               buf->vb.field  = field;
-               buf->tvnorm    = btv->tvnorm;
-               buf->fmt       = fmt;
-               redo_dma_risc = 1;
-       }
-
-       /* alloc risc memory */
-       if (STATE_NEEDS_INIT == buf->vb.state) {
-               redo_dma_risc = 1;
-               if (0 != (rc = videobuf_iolock(btv->c.pci,&buf->vb,&btv->fbuf)))
-                       goto fail;
-       }
-
-       if (redo_dma_risc)
-               if (0 != (rc = bttv_buffer_risc(btv,buf)))
-                       goto fail;
-
-       buf->vb.state = STATE_PREPARED;
-       return 0;
-
- fail:
-       bttv_dma_free(btv,buf);
-       return rc;
-}
-
-static int
-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
-       struct bttv_fh *fh = q->priv_data;
-
-       *size = fh->fmt->depth*fh->width*fh->height >> 3;
-       if (0 == *count)
-               *count = gbuffers;
-       while (*size * *count > gbuffers * gbufsize)
-               (*count)--;
-       return 0;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-              enum v4l2_field field)
-{
-       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
-       struct bttv_fh *fh = q->priv_data;
-
-       return bttv_prepare_buffer(fh->btv, buf, fh->fmt,
-                                  fh->width, fh->height, field);
-}
-
-static void
-buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
-       struct bttv_fh *fh = q->priv_data;
-       struct bttv    *btv = fh->btv;
-
-       buf->vb.state = STATE_QUEUED;
-       list_add_tail(&buf->vb.queue,&btv->capture);
-       if (!btv->curr.frame_irq) {
-               btv->loop_irq |= 1;
-               bttv_set_dma(btv, 0x03);
-       }
-}
-
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
-       struct bttv_fh *fh = q->priv_data;
-
-       bttv_dma_free(fh->btv,buf);
-}
-
-static struct videobuf_queue_ops bttv_video_qops = {
-       .buf_setup    = buffer_setup,
-       .buf_prepare  = buffer_prepare,
-       .buf_queue    = buffer_queue,
-       .buf_release  = buffer_release,
-};
-
-static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case BTTV_VERSION:
-               return BTTV_VERSION_CODE;
-
-       /* ***  v4l1  *** ************************************************ */
-       case VIDIOCGFREQ:
-       {
-               unsigned long *freq = arg;
-               *freq = btv->freq;
-               return 0;
-       }
-       case VIDIOCSFREQ:
-       {
-               unsigned long *freq = arg;
-               mutex_lock(&btv->lock);
-               btv->freq=*freq;
-               bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
-               if (btv->has_matchbox && btv->radio_user)
-                       tea5757_set_freq(btv,*freq);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner *v = arg;
-
-               if (UNSET == bttv_tvcards[btv->c.type].tuner)
-                       return -EINVAL;
-               if (v->tuner) /* Only tuner 0 */
-                       return -EINVAL;
-               strcpy(v->name, "Television");
-               v->rangelow  = 0;
-               v->rangehigh = 0x7FFFFFFF;
-               v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-               v->mode      = btv->tvnorm;
-               v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
-               bttv_call_i2c_clients(btv,cmd,v);
-               return 0;
-       }
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner *v = arg;
-
-               if (v->tuner) /* Only tuner 0 */
-                       return -EINVAL;
-               if (v->mode >= BTTV_TVNORMS)
-                       return -EINVAL;
-
-               mutex_lock(&btv->lock);
-               set_tvnorm(btv,v->mode);
-               bttv_call_i2c_clients(btv,cmd,v);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-               unsigned int channel = v->channel;
-
-               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               v->tuners=0;
-               v->flags = VIDEO_VC_AUDIO;
-               v->type = VIDEO_TYPE_CAMERA;
-               v->norm = btv->tvnorm;
-               if (channel == bttv_tvcards[btv->c.type].tuner)  {
-                       strcpy(v->name,"Television");
-                       v->flags|=VIDEO_VC_TUNER;
-                       v->type=VIDEO_TYPE_TV;
-                       v->tuners=1;
-               } else if (channel == btv->svhs) {
-                       strcpy(v->name,"S-Video");
-               } else {
-                       sprintf(v->name,"Composite%d",channel);
-               }
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-               unsigned int channel = v->channel;
-
-               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               if (v->norm >= BTTV_TVNORMS)
-                       return -EINVAL;
-
-               mutex_lock(&btv->lock);
-               if (channel == btv->input &&
-                   v->norm == btv->tvnorm) {
-                       /* nothing to do */
-                       mutex_unlock(&btv->lock);
-                       return 0;
-               }
-
-               btv->tvnorm = v->norm;
-               set_input(btv,v->channel);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-
-       case VIDIOCGAUDIO:
-       {
-               struct video_audio *v = arg;
-
-               memset(v,0,sizeof(*v));
-               strcpy(v->name,"Television");
-               v->flags |= VIDEO_AUDIO_MUTABLE;
-               v->mode  = VIDEO_SOUND_MONO;
-
-               mutex_lock(&btv->lock);
-               bttv_call_i2c_clients(btv,cmd,v);
-
-               /* card specific hooks */
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,v,0);
-
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOCSAUDIO:
-       {
-               struct video_audio *v = arg;
-               unsigned int audio = v->audio;
-
-               if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
-                       return -EINVAL;
-
-               mutex_lock(&btv->lock);
-               audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);
-               bttv_call_i2c_clients(btv,cmd,v);
-
-               /* card specific hooks */
-               if (btv->audio_hook)
-                       btv->audio_hook(btv,v,1);
-
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-
-       /* ***  v4l2  *** ************************************************ */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *e = arg;
-               unsigned int index = e->index;
-
-               if (index >= BTTV_TVNORMS)
-                       return -EINVAL;
-               v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
-                                        bttv_tvnorms[e->index].name);
-               e->index = index;
-               return 0;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-               *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
-               return 0;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               unsigned int i;
-
-               for (i = 0; i < BTTV_TVNORMS; i++)
-                       if (*id & bttv_tvnorms[i].v4l2_id)
-                               break;
-               if (i == BTTV_TVNORMS)
-                       return -EINVAL;
-
-               mutex_lock(&btv->lock);
-               set_tvnorm(btv,i);
-               i2c_vidiocschan(btv);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOC_QUERYSTD:
-       {
-               v4l2_std_id *id = arg;
-
-               if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
-                       *id = V4L2_STD_625_50;
-               else
-                       *id = V4L2_STD_525_60;
-               return 0;
-       }
-
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-               unsigned int n;
-
-               n = i->index;
-               if (n >= bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               memset(i,0,sizeof(*i));
-               i->index    = n;
-               i->type     = V4L2_INPUT_TYPE_CAMERA;
-               i->audioset = 0;
-               if (i->index == bttv_tvcards[btv->c.type].tuner) {
-                       sprintf(i->name, "Television");
-                       i->type  = V4L2_INPUT_TYPE_TUNER;
-                       i->tuner = 0;
-               } else if (i->index == btv->svhs) {
-                       sprintf(i->name, "S-Video");
-               } else {
-                       sprintf(i->name,"Composite%d",i->index);
-               }
-               if (i->index == btv->input) {
-                       __u32 dstatus = btread(BT848_DSTATUS);
-                       if (0 == (dstatus & BT848_DSTATUS_PRES))
-                               i->status |= V4L2_IN_ST_NO_SIGNAL;
-                       if (0 == (dstatus & BT848_DSTATUS_HLOC))
-                               i->status |= V4L2_IN_ST_NO_H_LOCK;
-               }
-               for (n = 0; n < BTTV_TVNORMS; n++)
-                       i->std |= bttv_tvnorms[n].v4l2_id;
-               return 0;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               int *i = arg;
-               *i = btv->input;
-               return 0;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               unsigned int *i = arg;
-
-               if (*i > bttv_tvcards[btv->c.type].video_inputs)
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               set_input(btv,*i);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-
-               if (UNSET == bttv_tvcards[btv->c.type].tuner)
-                       return -EINVAL;
-               if (0 != t->index)
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               memset(t,0,sizeof(*t));
-               strcpy(t->name, "Television");
-               t->type       = V4L2_TUNER_ANALOG_TV;
-               t->capability = V4L2_TUNER_CAP_NORM;
-               t->rxsubchans = V4L2_TUNER_SUB_MONO;
-               if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
-                       t->signal = 0xffff;
-               {
-                       struct video_tuner tuner;
-
-                       memset(&tuner, 0, sizeof (tuner));
-                       tuner.rangehigh = 0xffffffffUL;
-                       bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
-                       t->rangelow = tuner.rangelow;
-                       t->rangehigh = tuner.rangehigh;
-               }
-               {
-                       /* Hmmm ... */
-                       struct video_audio va;
-                       memset(&va, 0, sizeof(struct video_audio));
-                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-                       if (btv->audio_hook)
-                               btv->audio_hook(btv,&va,0);
-                       if(va.mode & VIDEO_SOUND_STEREO) {
-                               t->audmode     = V4L2_TUNER_MODE_STEREO;
-                               t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-                       }
-                       if(va.mode & VIDEO_SOUND_LANG1) {
-                               t->audmode    = V4L2_TUNER_MODE_LANG1;
-                               t->rxsubchans = V4L2_TUNER_SUB_LANG1
-                                       | V4L2_TUNER_SUB_LANG2;
-                       }
-               }
-               /* FIXME: fill capability+audmode */
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *t = arg;
-
-               if (UNSET == bttv_tvcards[btv->c.type].tuner)
-                       return -EINVAL;
-               if (0 != t->index)
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               {
-                       struct video_audio va;
-                       memset(&va, 0, sizeof(struct video_audio));
-                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-                       if (t->audmode == V4L2_TUNER_MODE_MONO)
-                               va.mode = VIDEO_SOUND_MONO;
-                       else if (t->audmode == V4L2_TUNER_MODE_STEREO)
-                               va.mode = VIDEO_SOUND_STEREO;
-                       else if (t->audmode == V4L2_TUNER_MODE_LANG1)
-                               va.mode = VIDEO_SOUND_LANG1;
-                       else if (t->audmode == V4L2_TUNER_MODE_LANG2)
-                               va.mode = VIDEO_SOUND_LANG2;
-                       bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
-                       if (btv->audio_hook)
-                               btv->audio_hook(btv,&va,1);
-               }
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
-
-               memset(f,0,sizeof(*f));
-               f->type = V4L2_TUNER_ANALOG_TV;
-               f->frequency = btv->freq;
-               return 0;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
-
-               if (unlikely(f->tuner != 0))
-                       return -EINVAL;
-               if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
-                       return -EINVAL;
-               mutex_lock(&btv->lock);
-               btv->freq = f->frequency;
-               bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
-               if (btv->has_matchbox && btv->radio_user)
-                       tea5757_set_freq(btv,btv->freq);
-               mutex_unlock(&btv->lock);
-               return 0;
-       }
-       case VIDIOC_LOG_STATUS:
-       {
-               bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
-               return 0;
-       }
-
-       default:
-               return -ENOIOCTLCMD;
-
-       }
-       return 0;
-}
-
-static int verify_window(const struct bttv_tvnorm *tvn,
-                        struct v4l2_window *win, int fixup)
-{
-       enum v4l2_field field;
-       int maxw, maxh;
-
-       if (win->w.width  < 48 || win->w.height < 32)
-               return -EINVAL;
-       if (win->clipcount > 2048)
-               return -EINVAL;
-
-       field = win->field;
-       maxw  = tvn->swidth;
-       maxh  = tvn->sheight;
-
-       if (V4L2_FIELD_ANY == field) {
-               field = (win->w.height > maxh/2)
-                       ? V4L2_FIELD_INTERLACED
-                       : V4L2_FIELD_TOP;
-       }
-       switch (field) {
-       case V4L2_FIELD_TOP:
-       case V4L2_FIELD_BOTTOM:
-               maxh = maxh / 2;
-               break;
-       case V4L2_FIELD_INTERLACED:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (!fixup && (win->w.width > maxw || win->w.height > maxh))
-               return -EINVAL;
-
-       if (win->w.width > maxw)
-               win->w.width = maxw;
-       if (win->w.height > maxh)
-               win->w.height = maxh;
-       win->field = field;
-       return 0;
-}
-
-static int setup_window(struct bttv_fh *fh, struct bttv *btv,
-                       struct v4l2_window *win, int fixup)
-{
-       struct v4l2_clip *clips = NULL;
-       int n,size,retval = 0;
-
-       if (NULL == fh->ovfmt)
-               return -EINVAL;
-       if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
-               return -EINVAL;
-       retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
-       if (0 != retval)
-               return retval;
-
-       /* copy clips  --  luckily v4l1 + v4l2 are binary
-          compatible here ...*/
-       n = win->clipcount;
-       size = sizeof(*clips)*(n+4);
-       clips = kmalloc(size,GFP_KERNEL);
-       if (NULL == clips)
-               return -ENOMEM;
-       if (n > 0) {
-               if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
-                       kfree(clips);
-                       return -EFAULT;
-               }
-       }
-       /* clip against screen */
-       if (NULL != btv->fbuf.base)
-               n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
-                                     &win->w, clips, n);
-       btcx_sort_clips(clips,n);
-
-       /* 4-byte alignments */
-       switch (fh->ovfmt->depth) {
-       case 8:
-       case 24:
-               btcx_align(&win->w, clips, n, 3);
-               break;
-       case 16:
-               btcx_align(&win->w, clips, n, 1);
-               break;
-       case 32:
-               /* no alignment fixups needed */
-               break;
-       default:
-               BUG();
-       }
-
-       mutex_lock(&fh->cap.lock);
-               kfree(fh->ov.clips);
-       fh->ov.clips    = clips;
-       fh->ov.nclips   = n;
-
-       fh->ov.w        = win->w;
-       fh->ov.field    = win->field;
-       fh->ov.setup_ok = 1;
-       btv->init.ov.w.width   = win->w.width;
-       btv->init.ov.w.height  = win->w.height;
-       btv->init.ov.field     = win->field;
-
-       /* update overlay if needed */
-       retval = 0;
-       if (check_btres(fh, RESOURCE_OVERLAY)) {
-               struct bttv_buffer *new;
-
-               new = videobuf_alloc(sizeof(*new));
-               bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-               retval = bttv_switch_overlay(btv,fh,new);
-       }
-       mutex_unlock(&fh->cap.lock);
-       return retval;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
-{
-       struct videobuf_queue* q = NULL;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               q = &fh->cap;
-               break;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               q = &fh->vbi;
-               break;
-       default:
-               BUG();
-       }
-       return q;
-}
-
-static int bttv_resource(struct bttv_fh *fh)
-{
-       int res = 0;
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               res = RESOURCE_VIDEO;
-               break;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               res = RESOURCE_VBI;
-               break;
-       default:
-               BUG();
-       }
-       return res;
-}
-
-static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
-{
-       struct videobuf_queue *q = bttv_queue(fh);
-       int res = bttv_resource(fh);
-
-       if (check_btres(fh,res))
-               return -EBUSY;
-       if (videobuf_queue_is_busy(q))
-               return -EBUSY;
-       fh->type = type;
-       return 0;
-}
-
-static void
-pix_format_set_size     (struct v4l2_pix_format *       f,
-                        const struct bttv_format *     fmt,
-                        unsigned int                   width,
-                        unsigned int                   height)
-{
-       f->width = width;
-       f->height = height;
-
-       if (fmt->flags & FORMAT_FLAGS_PLANAR) {
-               f->bytesperline = width; /* Y plane */
-               f->sizeimage = (width * height * fmt->depth) >> 3;
-       } else {
-               f->bytesperline = (width * fmt->depth) >> 3;
-               f->sizeimage = height * f->bytesperline;
-       }
-}
-
-static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
-{
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
-               pix_format_set_size (&f->fmt.pix, fh->fmt,
-                                    fh->width, fh->height);
-               f->fmt.pix.field        = fh->cap.field;
-               f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-               return 0;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               memset(&f->fmt.win,0,sizeof(struct v4l2_window));
-               f->fmt.win.w     = fh->ov.w;
-               f->fmt.win.field = fh->ov.field;
-               return 0;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               bttv_vbi_get_fmt(fh,f);
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
-                       struct v4l2_format *f)
-{
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               const struct bttv_format *fmt;
-               enum v4l2_field field;
-               unsigned int maxw,maxh;
-
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
-
-               /* fixup format */
-               maxw  = bttv_tvnorms[btv->tvnorm].swidth;
-               maxh  = bttv_tvnorms[btv->tvnorm].sheight;
-               field = f->fmt.pix.field;
-               if (V4L2_FIELD_ANY == field)
-                       field = (f->fmt.pix.height > maxh/2)
-                               ? V4L2_FIELD_INTERLACED
-                               : V4L2_FIELD_BOTTOM;
-               if (V4L2_FIELD_SEQ_BT == field)
-                       field = V4L2_FIELD_SEQ_TB;
-               switch (field) {
-               case V4L2_FIELD_TOP:
-               case V4L2_FIELD_BOTTOM:
-               case V4L2_FIELD_ALTERNATE:
-                       maxh = maxh/2;
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       break;
-               case V4L2_FIELD_SEQ_TB:
-                       if (fmt->flags & FORMAT_FLAGS_PLANAR)
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               /* update data for the application */
-               f->fmt.pix.field = field;
-               if (f->fmt.pix.width  < 48)
-                       f->fmt.pix.width  = 48;
-               if (f->fmt.pix.height < 32)
-                       f->fmt.pix.height = 32;
-               if (f->fmt.pix.width  > maxw)
-                       f->fmt.pix.width = maxw;
-               if (f->fmt.pix.height > maxh)
-                       f->fmt.pix.height = maxh;
-               pix_format_set_size (&f->fmt.pix, fmt,
-                                    f->fmt.pix.width & ~3,
-                                    f->fmt.pix.height);
-
-               return 0;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               return verify_window(&bttv_tvnorms[btv->tvnorm],
-                                    &f->fmt.win, 1);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               bttv_vbi_try_fmt(fh,f);
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
-                     struct v4l2_format *f)
-{
-       int retval;
-
-       switch (f->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-       {
-               const struct bttv_format *fmt;
-
-               retval = bttv_switch_type(fh,f->type);
-               if (0 != retval)
-                       return retval;
-               retval = bttv_try_fmt(fh,btv,f);
-               if (0 != retval)
-                       return retval;
-               fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-
-               /* update our state informations */
-               mutex_lock(&fh->cap.lock);
-               fh->fmt              = fmt;
-               fh->cap.field        = f->fmt.pix.field;
-               fh->cap.last         = V4L2_FIELD_NONE;
-               fh->width            = f->fmt.pix.width;
-               fh->height           = f->fmt.pix.height;
-               btv->init.fmt        = fmt;
-               btv->init.width      = f->fmt.pix.width;
-               btv->init.height     = f->fmt.pix.height;
-               mutex_unlock(&fh->cap.lock);
-
-               return 0;
-       }
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               if (no_overlay > 0) {
-                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-                       return -EINVAL;
-               }
-               return setup_window(fh, btv, &f->fmt.win, 1);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               retval = bttv_switch_type(fh,f->type);
-               if (0 != retval)
-                       return retval;
-               if (locked_btres(fh->btv, RESOURCE_VBI))
-                       return -EBUSY;
-               bttv_vbi_try_fmt(fh,f);
-               bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
-               bttv_vbi_get_fmt(fh,f);
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int bttv_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, void *arg)
-{
-       struct bttv_fh *fh  = file->private_data;
-       struct bttv    *btv = fh->btv;
-       unsigned long flags;
-       int retval = 0;
-
-       if (bttv_debug > 1)
-               v4l_print_ioctl(btv->c.name, cmd);
-
-       if (btv->errors)
-               bttv_reinit_bt848(btv);
-
-       switch (cmd) {
-       case VIDIOCSFREQ:
-       case VIDIOCSTUNER:
-       case VIDIOCSCHAN:
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-               retval = v4l2_prio_check(&btv->prio,&fh->prio);
-               if (0 != retval)
-                       return retval;
-       };
-
-       switch (cmd) {
-
-       /* ***  v4l1  *** ************************************************ */
-       case VIDIOCGCAP:
-       {
-               struct video_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->name,btv->video_dev->name);
-               if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-                       /* vbi */
-                       cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
-               } else {
-                       /* others */
-                       cap->type = VID_TYPE_CAPTURE|
-                               VID_TYPE_TUNER|
-                               VID_TYPE_CLIPPING|
-                               VID_TYPE_SCALES;
-                       if (no_overlay <= 0)
-                               cap->type |= VID_TYPE_OVERLAY;
-
-                       cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
-                       cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
-                       cap->minwidth  = 48;
-                       cap->minheight = 32;
-               }
-               cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
-               cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
-               return 0;
-       }
-
-       case VIDIOCGPICT:
-       {
-               struct video_picture *pic = arg;
-
-               memset(pic,0,sizeof(*pic));
-               pic->brightness = btv->bright;
-               pic->contrast   = btv->contrast;
-               pic->hue        = btv->hue;
-               pic->colour     = btv->saturation;
-               if (fh->fmt) {
-                       pic->depth   = fh->fmt->depth;
-                       pic->palette = fh->fmt->palette;
-               }
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *pic = arg;
-               const struct bttv_format *fmt;
-
-               fmt = format_by_palette(pic->palette);
-               if (NULL == fmt)
-                       return -EINVAL;
-               mutex_lock(&fh->cap.lock);
-               if (fmt->depth != pic->depth) {
-                       retval = -EINVAL;
-                       goto fh_unlock_and_return;
-               }
-               if (fmt->flags & FORMAT_FLAGS_RAW) {
-                       /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
-                          RAW_LINES * 2. F1 is stored at offset 0, F2
-                          at buffer size / 2. */
-                       fh->width = RAW_BPL;
-                       fh->height = gbufsize / RAW_BPL;
-                       btv->init.width  = RAW_BPL;
-                       btv->init.height = gbufsize / RAW_BPL;
-               }
-               fh->ovfmt   = fmt;
-               fh->fmt     = fmt;
-               btv->init.ovfmt   = fmt;
-               btv->init.fmt     = fmt;
-               if (bigendian) {
-                       /* dirty hack time:  swap bytes for overlay if the
-                          display adaptor is big endian (insmod option) */
-                       if (fmt->palette == VIDEO_PALETTE_RGB555 ||
-                           fmt->palette == VIDEO_PALETTE_RGB565 ||
-                           fmt->palette == VIDEO_PALETTE_RGB32) {
-                               fh->ovfmt = fmt+1;
-                       }
-               }
-               bt848_bright(btv,pic->brightness);
-               bt848_contrast(btv,pic->contrast);
-               bt848_hue(btv,pic->hue);
-               bt848_sat(btv,pic->colour);
-               mutex_unlock(&fh->cap.lock);
-               return 0;
-       }
-
-       case VIDIOCGWIN:
-       {
-               struct video_window *win = arg;
-
-               memset(win,0,sizeof(*win));
-               win->x      = fh->ov.w.left;
-               win->y      = fh->ov.w.top;
-               win->width  = fh->ov.w.width;
-               win->height = fh->ov.w.height;
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *win = arg;
-               struct v4l2_window w2;
-
-               if (no_overlay > 0) {
-                       printk ("VIDIOCSWIN: no_overlay\n");
-                       return -EINVAL;
-               }
-
-               w2.field = V4L2_FIELD_ANY;
-               w2.w.left    = win->x;
-               w2.w.top     = win->y;
-               w2.w.width   = win->width;
-               w2.w.height  = win->height;
-               w2.clipcount = win->clipcount;
-               w2.clips     = (struct v4l2_clip __user *)win->clips;
-               retval = setup_window(fh, btv, &w2, 0);
-               if (0 == retval) {
-                       /* on v4l1 this ioctl affects the read() size too */
-                       fh->width  = fh->ov.w.width;
-                       fh->height = fh->ov.w.height;
-                       btv->init.width  = fh->ov.w.width;
-                       btv->init.height = fh->ov.w.height;
-               }
-               return retval;
-       }
-
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *fbuf = arg;
-
-               fbuf->base          = btv->fbuf.base;
-               fbuf->width         = btv->fbuf.fmt.width;
-               fbuf->height        = btv->fbuf.fmt.height;
-               fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
-               if (fh->ovfmt)
-                       fbuf->depth = fh->ovfmt->depth;
-               return 0;
-       }
-       case VIDIOCSFBUF:
-       {
-               struct video_buffer *fbuf = arg;
-               const struct bttv_format *fmt;
-               unsigned long end;
-
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
-               end = (unsigned long)fbuf->base +
-                       fbuf->height * fbuf->bytesperline;
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
-
-               switch (fbuf->depth) {
-               case 8:
-                       fmt = format_by_palette(VIDEO_PALETTE_HI240);
-                       break;
-               case 16:
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB565);
-                       break;
-               case 24:
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB24);
-                       break;
-               case 32:
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB32);
-                       break;
-               case 15:
-                       fbuf->depth = 16;
-                       fmt = format_by_palette(VIDEO_PALETTE_RGB555);
-                       break;
-               default:
-                       fmt = NULL;
-                       break;
-               }
-               if (NULL == fmt)
-                       goto fh_unlock_and_return;
-
-               fh->ovfmt = fmt;
-               fh->fmt   = fmt;
-               btv->init.ovfmt = fmt;
-               btv->init.fmt   = fmt;
-               btv->fbuf.base             = fbuf->base;
-               btv->fbuf.fmt.width        = fbuf->width;
-               btv->fbuf.fmt.height       = fbuf->height;
-               if (fbuf->bytesperline)
-                       btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
-               else
-                       btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-               mutex_unlock(&fh->cap.lock);
-               return 0;
-       }
-
-       case VIDIOCCAPTURE:
-       case VIDIOC_OVERLAY:
-       {
-               struct bttv_buffer *new;
-               int *on = arg;
-
-               if (*on) {
-                       /* verify args */
-                       if (NULL == btv->fbuf.base)
-                               return -EINVAL;
-                       if (!fh->ov.setup_ok) {
-                               dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
-                               return -EINVAL;
-                       }
-               }
-
-               if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
-                       return -EBUSY;
-
-               mutex_lock(&fh->cap.lock);
-               if (*on) {
-                       fh->ov.tvnorm = btv->tvnorm;
-                       new = videobuf_alloc(sizeof(*new));
-                       bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-               } else {
-                       new = NULL;
-               }
-
-               /* switch over */
-               retval = bttv_switch_overlay(btv,fh,new);
-               mutex_unlock(&fh->cap.lock);
-               return retval;
-       }
-
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *mbuf = arg;
-               unsigned int i;
-
-               mutex_lock(&fh->cap.lock);
-               retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
-                                            V4L2_MEMORY_MMAP);
-               if (retval < 0)
-                       goto fh_unlock_and_return;
-               memset(mbuf,0,sizeof(*mbuf));
-               mbuf->frames = gbuffers;
-               mbuf->size   = gbuffers * gbufsize;
-               for (i = 0; i < gbuffers; i++)
-                       mbuf->offsets[i] = i * gbufsize;
-               mutex_unlock(&fh->cap.lock);
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-               struct bttv_buffer *buf;
-               enum v4l2_field field;
-
-               if (vm->frame >= VIDEO_MAX_FRAME)
-                       return -EINVAL;
-
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
-               buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
-               if (NULL == buf)
-                       goto fh_unlock_and_return;
-               if (0 == buf->vb.baddr)
-                       goto fh_unlock_and_return;
-               if (buf->vb.state == STATE_QUEUED ||
-                   buf->vb.state == STATE_ACTIVE)
-                       goto fh_unlock_and_return;
-
-               field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
-                       ? V4L2_FIELD_INTERLACED
-                       : V4L2_FIELD_BOTTOM;
-               retval = bttv_prepare_buffer(btv,buf,
-                                            format_by_palette(vm->format),
-                                            vm->width,vm->height,field);
-               if (0 != retval)
-                       goto fh_unlock_and_return;
-               spin_lock_irqsave(&btv->s_lock,flags);
-               buffer_queue(&fh->cap,&buf->vb);
-               spin_unlock_irqrestore(&btv->s_lock,flags);
-               mutex_unlock(&fh->cap.lock);
-               return 0;
-       }
-       case VIDIOCSYNC:
-       {
-               int *frame = arg;
-               struct bttv_buffer *buf;
-
-               if (*frame >= VIDEO_MAX_FRAME)
-                       return -EINVAL;
-
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
-               buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
-               if (NULL == buf)
-                       goto fh_unlock_and_return;
-               retval = videobuf_waiton(&buf->vb,0,1);
-               if (0 != retval)
-                       goto fh_unlock_and_return;
-               switch (buf->vb.state) {
-               case STATE_ERROR:
-                       retval = -EIO;
-                       /* fall through */
-               case STATE_DONE:
-                       videobuf_dma_pci_sync(btv->c.pci,&buf->vb.dma);
-                       bttv_dma_free(btv,buf);
-                       break;
-               default:
-                       retval = -EINVAL;
-                       break;
-               }
-               mutex_unlock(&fh->cap.lock);
-               return retval;
-       }
-
-       case VIDIOCGVBIFMT:
-       {
-               struct vbi_format *fmt = (void *) arg;
-               struct v4l2_format fmt2;
-
-               if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
-                       retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-                       if (0 != retval)
-                               return retval;
-               }
-               bttv_vbi_get_fmt(fh, &fmt2);
-
-               memset(fmt,0,sizeof(*fmt));
-               fmt->sampling_rate    = fmt2.fmt.vbi.sampling_rate;
-               fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
-               fmt->sample_format    = VIDEO_PALETTE_RAW;
-               fmt->start[0]         = fmt2.fmt.vbi.start[0];
-               fmt->count[0]         = fmt2.fmt.vbi.count[0];
-               fmt->start[1]         = fmt2.fmt.vbi.start[1];
-               fmt->count[1]         = fmt2.fmt.vbi.count[1];
-               if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
-                       fmt->flags   |= VBI_UNSYNC;
-               if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
-                       fmt->flags   |= VBI_INTERLACED;
-               return 0;
-       }
-       case VIDIOCSVBIFMT:
-       {
-               struct vbi_format *fmt = (void *) arg;
-               struct v4l2_format fmt2;
-
-               retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-               if (0 != retval)
-                       return retval;
-               bttv_vbi_get_fmt(fh, &fmt2);
-
-               if (fmt->sampling_rate    != fmt2.fmt.vbi.sampling_rate     ||
-                   fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line  ||
-                   fmt->sample_format    != VIDEO_PALETTE_RAW              ||
-                   fmt->start[0]         != fmt2.fmt.vbi.start[0]          ||
-                   fmt->start[1]         != fmt2.fmt.vbi.start[1]          ||
-                   fmt->count[0]         != fmt->count[1]                  ||
-                   fmt->count[0]         <  1                              ||
-                   fmt->count[0]         >  32 /* VBI_MAXLINES */)
-                       return -EINVAL;
-
-               bttv_vbi_setlines(fh,btv,fmt->count[0]);
-               return 0;
-       }
-
-       case BTTV_VERSION:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGCHAN:
-       case VIDIOCSCHAN:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return bttv_common_ioctls(btv,cmd,arg);
-
-       /* ***  v4l2  *** ************************************************ */
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = arg;
-
-               if (0 == v4l2)
-                       return -EINVAL;
-               memset(cap, 0, sizeof (*cap));
-               strlcpy(cap->driver, "bttv", sizeof (cap->driver));
-               strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
-               snprintf(cap->bus_info, sizeof (cap->bus_info),
-                        "PCI:%s", pci_name(btv->c.pci));
-               cap->version = BTTV_VERSION_CODE;
-               cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_VBI_CAPTURE |
-                       V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
-               if (no_overlay <= 0)
-                       cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
-
-               if (bttv_tvcards[btv->c.type].tuner != UNSET &&
-                   bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
-                       cap->capabilities |= V4L2_CAP_TUNER;
-               return 0;
-       }
-
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int i;
-               int index;
-
-               type  = f->type;
-               if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
-                       /* vbi */
-                       index = f->index;
-                       if (0 != index)
-                               return -EINVAL;
-                       memset(f,0,sizeof(*f));
-                       f->index       = index;
-                       f->type        = type;
-                       f->pixelformat = V4L2_PIX_FMT_GREY;
-                       strcpy(f->description,"vbi data");
-                       return 0;
-               }
-
-               /* video capture + overlay */
-               index = -1;
-               for (i = 0; i < BTTV_FORMATS; i++) {
-                       if (bttv_formats[i].fourcc != -1)
-                               index++;
-                       if ((unsigned int)index == f->index)
-                               break;
-               }
-               if (BTTV_FORMATS == i)
-                       return -EINVAL;
-
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               memset(f,0,sizeof(*f));
-               f->index       = index;
-               f->type        = type;
-               f->pixelformat = bttv_formats[i].fourcc;
-               strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
-               return 0;
-       }
-
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return bttv_try_fmt(fh,btv,f);
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return bttv_g_fmt(fh,f);
-       }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = arg;
-               return bttv_s_fmt(fh,btv,f);
-       }
-
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
-
-               *fb = btv->fbuf;
-               fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-               if (fh->ovfmt)
-                       fb->fmt.pixelformat  = fh->ovfmt->fourcc;
-               return 0;
-       }
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *fb = arg;
-               const struct bttv_format *fmt;
-
-               if(!capable(CAP_SYS_ADMIN) &&
-                  !capable(CAP_SYS_RAWIO))
-                       return -EPERM;
-
-               /* check args */
-               fmt = format_by_fourcc(fb->fmt.pixelformat);
-               if (NULL == fmt)
-                       return -EINVAL;
-               if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
-                       return -EINVAL;
-
-               mutex_lock(&fh->cap.lock);
-               retval = -EINVAL;
-               if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-                       if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
-                               goto fh_unlock_and_return;
-                       if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
-                               goto fh_unlock_and_return;
-               }
-
-               /* ok, accept it */
-               btv->fbuf.base       = fb->base;
-               btv->fbuf.fmt.width  = fb->fmt.width;
-               btv->fbuf.fmt.height = fb->fmt.height;
-               if (0 != fb->fmt.bytesperline)
-                       btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
-               else
-                       btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
-
-               retval = 0;
-               fh->ovfmt = fmt;
-               btv->init.ovfmt = fmt;
-               if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-                       fh->ov.w.left   = 0;
-                       fh->ov.w.top    = 0;
-                       fh->ov.w.width  = fb->fmt.width;
-                       fh->ov.w.height = fb->fmt.height;
-                       btv->init.ov.w.width  = fb->fmt.width;
-                       btv->init.ov.w.height = fb->fmt.height;
-                               kfree(fh->ov.clips);
-                       fh->ov.clips = NULL;
-                       fh->ov.nclips = 0;
-
-                       if (check_btres(fh, RESOURCE_OVERLAY)) {
-                               struct bttv_buffer *new;
-
-                               new = videobuf_alloc(sizeof(*new));
-                               bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
-                               retval = bttv_switch_overlay(btv,fh,new);
-                       }
-               }
-               mutex_unlock(&fh->cap.lock);
-               return retval;
-       }
-
-       case VIDIOC_REQBUFS:
-               return videobuf_reqbufs(bttv_queue(fh),arg);
-
-       case VIDIOC_QUERYBUF:
-               return videobuf_querybuf(bttv_queue(fh),arg);
-
-       case VIDIOC_QBUF:
-               return videobuf_qbuf(bttv_queue(fh),arg);
-
-       case VIDIOC_DQBUF:
-               return videobuf_dqbuf(bttv_queue(fh),arg,
-                                     file->f_flags & O_NONBLOCK);
-
-       case VIDIOC_STREAMON:
-       {
-               int res = bttv_resource(fh);
-
-               if (!check_alloc_btres(btv,fh,res))
-                       return -EBUSY;
-               return videobuf_streamon(bttv_queue(fh));
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int res = bttv_resource(fh);
-
-               retval = videobuf_streamoff(bttv_queue(fh));
-               if (retval < 0)
-                       return retval;
-               free_btres(btv,fh,res);
-               return 0;
-       }
-
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *c = arg;
-               int i;
-
-               if ((c->id <  V4L2_CID_BASE ||
-                    c->id >= V4L2_CID_LASTP1) &&
-                   (c->id <  V4L2_CID_PRIVATE_BASE ||
-                    c->id >= V4L2_CID_PRIVATE_LASTP1))
-                       return -EINVAL;
-               for (i = 0; i < BTTV_CTLS; i++)
-                       if (bttv_ctls[i].id == c->id)
-                               break;
-               if (i == BTTV_CTLS) {
-                       *c = no_ctl;
-                       return 0;
-               }
-               *c = bttv_ctls[i];
-               if (i >= 4 && i <= 8) {
-                       struct video_audio va;
-                       memset(&va,0,sizeof(va));
-                       bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
-                       if (btv->audio_hook)
-                               btv->audio_hook(btv,&va,0);
-                       switch (bttv_ctls[i].id) {
-                       case V4L2_CID_AUDIO_VOLUME:
-                               if (!(va.flags & VIDEO_AUDIO_VOLUME))
-                                       *c = no_ctl;
-                               break;
-                       case V4L2_CID_AUDIO_BALANCE:
-                               if (!(va.flags & VIDEO_AUDIO_BALANCE))
-                                       *c = no_ctl;
-                               break;
-                       case V4L2_CID_AUDIO_BASS:
-                               if (!(va.flags & VIDEO_AUDIO_BASS))
-                                       *c = no_ctl;
-                               break;
-                       case V4L2_CID_AUDIO_TREBLE:
-                               if (!(va.flags & VIDEO_AUDIO_TREBLE))
-                                       *c = no_ctl;
-                               break;
-                       }
-               }
-               return 0;
-       }
-       case VIDIOC_G_CTRL:
-               return get_control(btv,arg);
-       case VIDIOC_S_CTRL:
-               return set_control(btv,arg);
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm *parm = arg;
-               struct v4l2_standard s;
-               if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-               memset(parm,0,sizeof(*parm));
-               v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
-                                        bttv_tvnorms[btv->tvnorm].name);
-               parm->parm.capture.timeperframe = s.frameperiod;
-               return 0;
-       }
-
-       case VIDIOC_G_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
-
-               *p = v4l2_prio_max(&btv->prio);
-               return 0;
-       }
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *prio = arg;
-
-               return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
-       }
-
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_ENUMINPUT:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_G_TUNER:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
-       case VIDIOC_LOG_STATUS:
-               return bttv_common_ioctls(btv,cmd,arg);
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-
- fh_unlock_and_return:
-       mutex_unlock(&fh->cap.lock);
-       return retval;
-}
-
-static int bttv_ioctl(struct inode *inode, struct file *file,
-                     unsigned int cmd, unsigned long arg)
-{
-       struct bttv_fh *fh  = file->private_data;
-
-       switch (cmd) {
-       case BTTV_VBISIZE:
-               bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-               return fh->lines * 2 * 2048;
-       default:
-               return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
-       }
-}
-
-static ssize_t bttv_read(struct file *file, char __user *data,
-                        size_t count, loff_t *ppos)
-{
-       struct bttv_fh *fh = file->private_data;
-       int retval = 0;
-
-       if (fh->btv->errors)
-               bttv_reinit_bt848(fh->btv);
-       dprintk("bttv%d: read count=%d type=%s\n",
-               fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
-
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (locked_btres(fh->btv,RESOURCE_VIDEO))
-                       return -EBUSY;
-               retval = videobuf_read_one(&fh->cap, data, count, ppos,
-                                          file->f_flags & O_NONBLOCK);
-               break;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
-               if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
-                       return -EBUSY;
-               retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
-                                             file->f_flags & O_NONBLOCK);
-               break;
-       default:
-               BUG();
-       }
-       return retval;
-}
-
-static unsigned int bttv_poll(struct file *file, poll_table *wait)
-{
-       struct bttv_fh *fh = file->private_data;
-       struct bttv_buffer *buf;
-       enum v4l2_field field;
-
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-               if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
-                       return POLLERR;
-               return videobuf_poll_stream(file, &fh->vbi, wait);
-       }
-
-       if (check_btres(fh,RESOURCE_VIDEO)) {
-               /* streaming capture */
-               if (list_empty(&fh->cap.stream))
-                       return POLLERR;
-               buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
-       } else {
-               /* read() capture */
-               mutex_lock(&fh->cap.lock);
-               if (NULL == fh->cap.read_buf) {
-                       /* need to capture a new frame */
-                       if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
-                               mutex_unlock(&fh->cap.lock);
-                               return POLLERR;
-                       }
-                       fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
-                       if (NULL == fh->cap.read_buf) {
-                               mutex_unlock(&fh->cap.lock);
-                               return POLLERR;
-                       }
-                       fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
-                       field = videobuf_next_field(&fh->cap);
-                       if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
-                               kfree (fh->cap.read_buf);
-                               fh->cap.read_buf = NULL;
-                               mutex_unlock(&fh->cap.lock);
-                               return POLLERR;
-                       }
-                       fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
-                       fh->cap.read_off = 0;
-               }
-               mutex_unlock(&fh->cap.lock);
-               buf = (struct bttv_buffer*)fh->cap.read_buf;
-       }
-
-       poll_wait(file, &buf->vb.done, wait);
-       if (buf->vb.state == STATE_DONE ||
-           buf->vb.state == STATE_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
-}
-
-static int bttv_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct bttv *btv = NULL;
-       struct bttv_fh *fh;
-       enum v4l2_buf_type type = 0;
-       unsigned int i;
-
-       dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
-
-       for (i = 0; i < bttv_num; i++) {
-               if (bttvs[i].video_dev &&
-                   bttvs[i].video_dev->minor == minor) {
-                       btv = &bttvs[i];
-                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       break;
-               }
-               if (bttvs[i].vbi_dev &&
-                   bttvs[i].vbi_dev->minor == minor) {
-                       btv = &bttvs[i];
-                       type = V4L2_BUF_TYPE_VBI_CAPTURE;
-                       break;
-               }
-       }
-       if (NULL == btv)
-               return -ENODEV;
-
-       dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
-               btv->c.nr,v4l2_type_names[type]);
-
-       /* allocate per filehandle data */
-       fh = kmalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh)
-               return -ENOMEM;
-       file->private_data = fh;
-       *fh = btv->init;
-       fh->type = type;
-       fh->ov.setup_ok = 0;
-       v4l2_prio_open(&btv->prio,&fh->prio);
-
-       videobuf_queue_init(&fh->cap, &bttv_video_qops,
-                           btv->c.pci, &btv->s_lock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_INTERLACED,
-                           sizeof(struct bttv_buffer),
-                           fh);
-       videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
-                           btv->c.pci, &btv->s_lock,
-                           V4L2_BUF_TYPE_VBI_CAPTURE,
-                           V4L2_FIELD_SEQ_TB,
-                           sizeof(struct bttv_buffer),
-                           fh);
-       i2c_vidiocschan(btv);
-
-       btv->users++;
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
-               bttv_vbi_setlines(fh,btv,16);
-       bttv_field_count(btv);
-       return 0;
-}
-
-static int bttv_release(struct inode *inode, struct file *file)
-{
-       struct bttv_fh *fh = file->private_data;
-       struct bttv *btv = fh->btv;
-
-       /* turn off overlay */
-       if (check_btres(fh, RESOURCE_OVERLAY))
-               bttv_switch_overlay(btv,fh,NULL);
-
-       /* stop video capture */
-       if (check_btres(fh, RESOURCE_VIDEO)) {
-               videobuf_streamoff(&fh->cap);
-               free_btres(btv,fh,RESOURCE_VIDEO);
-       }
-       if (fh->cap.read_buf) {
-               buffer_release(&fh->cap,fh->cap.read_buf);
-               kfree(fh->cap.read_buf);
-       }
-
-       /* stop vbi capture */
-       if (check_btres(fh, RESOURCE_VBI)) {
-               if (fh->vbi.streaming)
-                       videobuf_streamoff(&fh->vbi);
-               if (fh->vbi.reading)
-                       videobuf_read_stop(&fh->vbi);
-               free_btres(btv,fh,RESOURCE_VBI);
-       }
-
-       /* free stuff */
-       videobuf_mmap_free(&fh->cap);
-       videobuf_mmap_free(&fh->vbi);
-       v4l2_prio_close(&btv->prio,&fh->prio);
-       file->private_data = NULL;
-       kfree(fh);
-
-       btv->users--;
-       bttv_field_count(btv);
-       return 0;
-}
-
-static int
-bttv_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct bttv_fh *fh = file->private_data;
-
-       dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
-               fh->btv->c.nr, v4l2_type_names[fh->type],
-               vma->vm_start, vma->vm_end - vma->vm_start);
-       return videobuf_mmap_mapper(bttv_queue(fh),vma);
-}
-
-static struct file_operations bttv_fops =
-{
-       .owner    = THIS_MODULE,
-       .open     = bttv_open,
-       .release  = bttv_release,
-       .ioctl    = bttv_ioctl,
-       .compat_ioctl   = v4l_compat_ioctl32,
-       .llseek   = no_llseek,
-       .read     = bttv_read,
-       .mmap     = bttv_mmap,
-       .poll     = bttv_poll,
-};
-
-static struct video_device bttv_video_template =
-{
-       .name     = "UNSET",
-       .type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-                   VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-       .hardware = VID_HARDWARE_BT848,
-       .fops     = &bttv_fops,
-       .minor    = -1,
-};
-
-static struct video_device bttv_vbi_template =
-{
-       .name     = "bt848/878 vbi",
-       .type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
-       .hardware = VID_HARDWARE_BT848,
-       .fops     = &bttv_fops,
-       .minor    = -1,
-};
-
-/* ----------------------------------------------------------------------- */
-/* radio interface                                                         */
-
-static int radio_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct bttv *btv = NULL;
-       unsigned int i;
-
-       dprintk("bttv: open minor=%d\n",minor);
-
-       for (i = 0; i < bttv_num; i++) {
-               if (bttvs[i].radio_dev->minor == minor) {
-                       btv = &bttvs[i];
-                       break;
-               }
-       }
-       if (NULL == btv)
-               return -ENODEV;
-
-       dprintk("bttv%d: open called (radio)\n",btv->c.nr);
-       mutex_lock(&btv->lock);
-
-       btv->radio_user++;
-
-       file->private_data = btv;
-
-       bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
-       audio_mux(btv,AUDIO_RADIO);
-
-       mutex_unlock(&btv->lock);
-       return 0;
-}
-
-static int radio_release(struct inode *inode, struct file *file)
-{
-       struct bttv        *btv = file->private_data;
-       struct rds_command cmd;
-
-       btv->radio_user--;
-
-       bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
-
-       return 0;
-}
-
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
-{
-       struct bttv    *btv = file->private_data;
-
-       switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *cap = arg;
-
-               memset(cap,0,sizeof(*cap));
-               strcpy(cap->name,btv->radio_dev->name);
-               cap->type = VID_TYPE_TUNER;
-               cap->channels = 1;
-               cap->audios = 1;
-               return 0;
-       }
-
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner *v = arg;
-
-               if(v->tuner)
-                       return -EINVAL;
-               memset(v,0,sizeof(*v));
-               strcpy(v->name, "Radio");
-               bttv_call_i2c_clients(btv,cmd,v);
-               return 0;
-       }
-       case VIDIOCSTUNER:
-               /* nothing to do */
-               return 0;
-
-       case BTTV_VERSION:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-       case VIDIOC_LOG_STATUS:
-               return bttv_common_ioctls(btv,cmd,arg);
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int radio_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-}
-
-static ssize_t radio_read(struct file *file, char __user *data,
-                        size_t count, loff_t *ppos)
-{
-       struct bttv    *btv = file->private_data;
-       struct rds_command cmd;
-       cmd.block_count = count/3;
-       cmd.buffer = data;
-       cmd.instance = file;
-       cmd.result = -ENODEV;
-
-       bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
-
-       return cmd.result;
-}
-
-static unsigned int radio_poll(struct file *file, poll_table *wait)
-{
-       struct bttv    *btv = file->private_data;
-       struct rds_command cmd;
-       cmd.instance = file;
-       cmd.event_list = wait;
-       cmd.result = -ENODEV;
-       bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
-
-       return cmd.result;
-}
-
-static struct file_operations radio_fops =
-{
-       .owner    = THIS_MODULE,
-       .open     = radio_open,
-       .read     = radio_read,
-       .release  = radio_release,
-       .ioctl    = radio_ioctl,
-       .llseek   = no_llseek,
-       .poll     = radio_poll,
-};
-
-static struct video_device radio_template =
-{
-       .name     = "bt848/878 radio",
-       .type     = VID_TYPE_TUNER,
-       .hardware = VID_HARDWARE_BT848,
-       .fops     = &radio_fops,
-       .minor    = -1,
-};
-
-/* ----------------------------------------------------------------------- */
-/* some debug code                                                         */
-
-static int bttv_risc_decode(u32 risc)
-{
-       static char *instr[16] = {
-               [ BT848_RISC_WRITE     >> 28 ] = "write",
-               [ BT848_RISC_SKIP      >> 28 ] = "skip",
-               [ BT848_RISC_WRITEC    >> 28 ] = "writec",
-               [ BT848_RISC_JUMP      >> 28 ] = "jump",
-               [ BT848_RISC_SYNC      >> 28 ] = "sync",
-               [ BT848_RISC_WRITE123  >> 28 ] = "write123",
-               [ BT848_RISC_SKIP123   >> 28 ] = "skip123",
-               [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
-       };
-       static int incr[16] = {
-               [ BT848_RISC_WRITE     >> 28 ] = 2,
-               [ BT848_RISC_JUMP      >> 28 ] = 2,
-               [ BT848_RISC_SYNC      >> 28 ] = 2,
-               [ BT848_RISC_WRITE123  >> 28 ] = 5,
-               [ BT848_RISC_SKIP123   >> 28 ] = 2,
-               [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
-       };
-       static char *bits[] = {
-               "be0",  "be1",  "be2",  "be3/resync",
-               "set0", "set1", "set2", "set3",
-               "clr0", "clr1", "clr2", "clr3",
-               "irq",  "res",  "eol",  "sol",
-       };
-       int i;
-
-       printk("0x%08x [ %s", risc,
-              instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
-       for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
-               if (risc & (1 << (i + 12)))
-                       printk(" %s",bits[i]);
-       printk(" count=%d ]\n", risc & 0xfff);
-       return incr[risc >> 28] ? incr[risc >> 28] : 1;
-}
-
-static void bttv_risc_disasm(struct bttv *btv,
-                            struct btcx_riscmem *risc)
-{
-       unsigned int i,j,n;
-
-       printk("%s: risc disasm: %p [dma=0x%08lx]\n",
-              btv->c.name, risc->cpu, (unsigned long)risc->dma);
-       for (i = 0; i < (risc->size >> 2); i += n) {
-               printk("%s:   0x%lx: ", btv->c.name,
-                      (unsigned long)(risc->dma + (i<<2)));
-               n = bttv_risc_decode(risc->cpu[i]);
-               for (j = 1; j < n; j++)
-                       printk("%s:   0x%lx: 0x%08x [ arg #%d ]\n",
-                              btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
-                              risc->cpu[i+j], j);
-               if (0 == risc->cpu[i])
-                       break;
-       }
-}
-
-static void bttv_print_riscaddr(struct bttv *btv)
-{
-       printk("  main: %08Lx\n",
-              (unsigned long long)btv->main.dma);
-       printk("  vbi : o=%08Lx e=%08Lx\n",
-              btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
-              btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
-       printk("  cap : o=%08Lx e=%08Lx\n",
-              btv->curr.top    ? (unsigned long long)btv->curr.top->top.dma : 0,
-              btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
-       printk("  scr : o=%08Lx e=%08Lx\n",
-              btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
-              btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
-       bttv_risc_disasm(btv, &btv->main);
-}
-
-/* ----------------------------------------------------------------------- */
-/* irq handler                                                             */
-
-static char *irq_name[] = {
-       "FMTCHG",  // format change detected (525 vs. 625)
-       "VSYNC",   // vertical sync (new field)
-       "HSYNC",   // horizontal sync
-       "OFLOW",   // chroma/luma AGC overflow
-       "HLOCK",   // horizontal lock changed
-       "VPRES",   // video presence changed
-       "6", "7",
-       "I2CDONE", // hw irc operation finished
-       "GPINT",   // gpio port triggered irq
-       "10",
-       "RISCI",   // risc instruction triggered irq
-       "FBUS",    // pixel data fifo dropped data (high pci bus latencies)
-       "FTRGT",   // pixel data fifo overrun
-       "FDSR",    // fifo data stream resyncronisation
-       "PPERR",   // parity error (data transfer)
-       "RIPERR",  // parity error (read risc instructions)
-       "PABORT",  // pci abort
-       "OCERR",   // risc instruction error
-       "SCERR",   // syncronisation error
-};
-
-static void bttv_print_irqbits(u32 print, u32 mark)
-{
-       unsigned int i;
-
-       printk("bits:");
-       for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
-               if (print & (1 << i))
-                       printk(" %s",irq_name[i]);
-               if (mark & (1 << i))
-                       printk("*");
-       }
-}
-
-static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
-{
-       printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
-              btv->c.nr,
-              (unsigned long)btv->main.dma,
-              (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
-              (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
-              (unsigned long)rc);
-
-       if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
-               printk("bttv%d: Oh, there (temporarely?) is no input signal. "
-                      "Ok, then this is harmless, don't worry ;)\n",
-                      btv->c.nr);
-               return;
-       }
-       printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
-              btv->c.nr);
-       printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
-              btv->c.nr);
-       dump_stack();
-}
-
-static int
-bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
-{
-       struct bttv_buffer *item;
-
-       memset(set,0,sizeof(*set));
-
-       /* capture request ? */
-       if (!list_empty(&btv->capture)) {
-               set->frame_irq = 1;
-               item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
-               if (V4L2_FIELD_HAS_TOP(item->vb.field))
-                       set->top    = item;
-               if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
-                       set->bottom = item;
-
-               /* capture request for other field ? */
-               if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
-                   (item->vb.queue.next != &btv->capture)) {
-                       item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
-                       if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
-                               if (NULL == set->top &&
-                                   V4L2_FIELD_TOP == item->vb.field) {
-                                       set->top = item;
-                               }
-                               if (NULL == set->bottom &&
-                                   V4L2_FIELD_BOTTOM == item->vb.field) {
-                                       set->bottom = item;
-                               }
-                               if (NULL != set->top  &&  NULL != set->bottom)
-                                       set->top_irq = 2;
-                       }
-               }
-       }
-
-       /* screen overlay ? */
-       if (NULL != btv->screen) {
-               if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
-                       if (NULL == set->top && NULL == set->bottom) {
-                               set->top    = btv->screen;
-                               set->bottom = btv->screen;
-                       }
-               } else {
-                       if (V4L2_FIELD_TOP == btv->screen->vb.field &&
-                           NULL == set->top) {
-                               set->top = btv->screen;
-                       }
-                       if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
-                           NULL == set->bottom) {
-                               set->bottom = btv->screen;
-                       }
-               }
-       }
-
-       dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
-               btv->c.nr,set->top, set->bottom,
-               btv->screen,set->frame_irq,set->top_irq);
-       return 0;
-}
-
-static void
-bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
-                     struct bttv_buffer_set *curr, unsigned int state)
-{
-       struct timeval ts;
-
-       do_gettimeofday(&ts);
-
-       if (wakeup->top == wakeup->bottom) {
-               if (NULL != wakeup->top && curr->top != wakeup->top) {
-                       if (irq_debug > 1)
-                               printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
-                       wakeup->top->vb.ts = ts;
-                       wakeup->top->vb.field_count = btv->field_count;
-                       wakeup->top->vb.state = state;
-                       wake_up(&wakeup->top->vb.done);
-               }
-       } else {
-               if (NULL != wakeup->top && curr->top != wakeup->top) {
-                       if (irq_debug > 1)
-                               printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
-                       wakeup->top->vb.ts = ts;
-                       wakeup->top->vb.field_count = btv->field_count;
-                       wakeup->top->vb.state = state;
-                       wake_up(&wakeup->top->vb.done);
-               }
-               if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
-                       if (irq_debug > 1)
-                               printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
-                       wakeup->bottom->vb.ts = ts;
-                       wakeup->bottom->vb.field_count = btv->field_count;
-                       wakeup->bottom->vb.state = state;
-                       wake_up(&wakeup->bottom->vb.done);
-               }
-       }
-}
-
-static void
-bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
-                   unsigned int state)
-{
-       struct timeval ts;
-
-       if (NULL == wakeup)
-               return;
-
-       do_gettimeofday(&ts);
-       wakeup->vb.ts = ts;
-       wakeup->vb.field_count = btv->field_count;
-       wakeup->vb.state = state;
-       wake_up(&wakeup->vb.done);
-}
-
-static void bttv_irq_timeout(unsigned long data)
-{
-       struct bttv *btv = (struct bttv *)data;
-       struct bttv_buffer_set old,new;
-       struct bttv_buffer *ovbi;
-       struct bttv_buffer *item;
-       unsigned long flags;
-
-       if (bttv_verbose) {
-               printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
-                      btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
-                      btread(BT848_RISC_COUNT));
-               bttv_print_irqbits(btread(BT848_INT_STAT),0);
-               printk("\n");
-       }
-
-       spin_lock_irqsave(&btv->s_lock,flags);
-
-       /* deactivate stuff */
-       memset(&new,0,sizeof(new));
-       old  = btv->curr;
-       ovbi = btv->cvbi;
-       btv->curr = new;
-       btv->cvbi = NULL;
-       btv->loop_irq = 0;
-       bttv_buffer_activate_video(btv, &new);
-       bttv_buffer_activate_vbi(btv,   NULL);
-       bttv_set_dma(btv, 0);
-
-       /* wake up */
-       bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
-       bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
-
-       /* cancel all outstanding capture / vbi requests */
-       while (!list_empty(&btv->capture)) {
-               item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
-               list_del(&item->vb.queue);
-               item->vb.state = STATE_ERROR;
-               wake_up(&item->vb.done);
-       }
-       while (!list_empty(&btv->vcapture)) {
-               item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
-               list_del(&item->vb.queue);
-               item->vb.state = STATE_ERROR;
-               wake_up(&item->vb.done);
-       }
-
-       btv->errors++;
-       spin_unlock_irqrestore(&btv->s_lock,flags);
-}
-
-static void
-bttv_irq_wakeup_top(struct bttv *btv)
-{
-       struct bttv_buffer *wakeup = btv->curr.top;
-
-       if (NULL == wakeup)
-               return;
-
-       spin_lock(&btv->s_lock);
-       btv->curr.top_irq = 0;
-       btv->curr.top = NULL;
-       bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
-
-       do_gettimeofday(&wakeup->vb.ts);
-       wakeup->vb.field_count = btv->field_count;
-       wakeup->vb.state = STATE_DONE;
-       wake_up(&wakeup->vb.done);
-       spin_unlock(&btv->s_lock);
-}
-
-static inline int is_active(struct btcx_riscmem *risc, u32 rc)
-{
-       if (rc < risc->dma)
-               return 0;
-       if (rc > risc->dma + risc->size)
-               return 0;
-       return 1;
-}
-
-static void
-bttv_irq_switch_video(struct bttv *btv)
-{
-       struct bttv_buffer_set new;
-       struct bttv_buffer_set old;
-       dma_addr_t rc;
-
-       spin_lock(&btv->s_lock);
-
-       /* new buffer set */
-       bttv_irq_next_video(btv, &new);
-       rc = btread(BT848_RISC_COUNT);
-       if ((btv->curr.top    && is_active(&btv->curr.top->top,       rc)) ||
-           (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
-               btv->framedrop++;
-               if (debug_latency)
-                       bttv_irq_debug_low_latency(btv, rc);
-               spin_unlock(&btv->s_lock);
-               return;
-       }
-
-       /* switch over */
-       old = btv->curr;
-       btv->curr = new;
-       btv->loop_irq &= ~1;
-       bttv_buffer_activate_video(btv, &new);
-       bttv_set_dma(btv, 0);
-
-       /* switch input */
-       if (UNSET != btv->new_input) {
-               video_mux(btv,btv->new_input);
-               btv->new_input = UNSET;
-       }
-
-       /* wake up finished buffers */
-       bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
-       spin_unlock(&btv->s_lock);
-}
-
-static void
-bttv_irq_switch_vbi(struct bttv *btv)
-{
-       struct bttv_buffer *new = NULL;
-       struct bttv_buffer *old;
-       u32 rc;
-
-       spin_lock(&btv->s_lock);
-
-       if (!list_empty(&btv->vcapture))
-               new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
-       old = btv->cvbi;
-
-       rc = btread(BT848_RISC_COUNT);
-       if (NULL != old && (is_active(&old->top,    rc) ||
-                           is_active(&old->bottom, rc))) {
-               btv->framedrop++;
-               if (debug_latency)
-                       bttv_irq_debug_low_latency(btv, rc);
-               spin_unlock(&btv->s_lock);
-               return;
-       }
-
-       /* switch */
-       btv->cvbi = new;
-       btv->loop_irq &= ~4;
-       bttv_buffer_activate_vbi(btv, new);
-       bttv_set_dma(btv, 0);
-
-       bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
-       spin_unlock(&btv->s_lock);
-}
-
-static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
-{
-       u32 stat,astat;
-       u32 dstat;
-       int count;
-       struct bttv *btv;
-       int handled = 0;
-
-       btv=(struct bttv *)dev_id;
-
-       if (btv->custom_irq)
-               handled = btv->custom_irq(btv);
-
-       count=0;
-       while (1) {
-               /* get/clear interrupt status bits */
-               stat=btread(BT848_INT_STAT);
-               astat=stat&btread(BT848_INT_MASK);
-               if (!astat)
-                       break;
-               handled = 1;
-               btwrite(stat,BT848_INT_STAT);
-
-               /* get device status bits */
-               dstat=btread(BT848_DSTATUS);
-
-               if (irq_debug) {
-                       printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
-                              "riscs=%x, riscc=%08x, ",
-                              btv->c.nr, count, btv->field_count,
-                              stat>>28, btread(BT848_RISC_COUNT));
-                       bttv_print_irqbits(stat,astat);
-                       if (stat & BT848_INT_HLOCK)
-                               printk("   HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
-                                      ? "yes" : "no");
-                       if (stat & BT848_INT_VPRES)
-                               printk("   PRES => %s", (dstat & BT848_DSTATUS_PRES)
-                                      ? "yes" : "no");
-                       if (stat & BT848_INT_FMTCHG)
-                               printk("   NUML => %s", (dstat & BT848_DSTATUS_NUML)
-                                      ? "625" : "525");
-                       printk("\n");
-               }
-
-               if (astat&BT848_INT_VSYNC)
-                       btv->field_count++;
-
-               if ((astat & BT848_INT_GPINT) && btv->remote) {
-                       wake_up(&btv->gpioq);
-                       bttv_input_irq(btv);
-               }
-
-               if (astat & BT848_INT_I2CDONE) {
-                       btv->i2c_done = stat;
-                       wake_up(&btv->i2c_queue);
-               }
-
-               if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
-                       bttv_irq_switch_vbi(btv);
-
-               if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
-                       bttv_irq_wakeup_top(btv);
-
-               if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
-                       bttv_irq_switch_video(btv);
-
-               if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
-                       audio_mux(btv, -1);
-
-               if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
-                       printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
-                              (astat & BT848_INT_SCERR) ? "SCERR" : "",
-                              (astat & BT848_INT_OCERR) ? "OCERR" : "",
-                              btread(BT848_RISC_COUNT));
-                       bttv_print_irqbits(stat,astat);
-                       printk("\n");
-                       if (bttv_debug)
-                               bttv_print_riscaddr(btv);
-               }
-               if (fdsr && astat & BT848_INT_FDSR) {
-                       printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
-                              btv->c.nr,btread(BT848_RISC_COUNT));
-                       if (bttv_debug)
-                               bttv_print_riscaddr(btv);
-               }
-
-               count++;
-               if (count > 4) {
-
-                       if (count > 8 || !(astat & BT848_INT_GPINT)) {
-                               btwrite(0, BT848_INT_MASK);
-
-                               printk(KERN_ERR
-                                          "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
-                       } else {
-                               printk(KERN_ERR
-                                          "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
-
-                               btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
-                                               BT848_INT_MASK);
-                       };
-
-                       bttv_print_irqbits(stat,astat);
-
-                       printk("]\n");
-               }
-       }
-       btv->irq_total++;
-       if (handled)
-               btv->irq_me++;
-       return IRQ_RETVAL(handled);
-}
-
-
-/* ----------------------------------------------------------------------- */
-/* initialitation                                                          */
-
-static struct video_device *vdev_init(struct bttv *btv,
-                                     struct video_device *template,
-                                     char *type)
-{
-       struct video_device *vfd;
-
-       vfd = video_device_alloc();
-       if (NULL == vfd)
-               return NULL;
-       *vfd = *template;
-       vfd->minor   = -1;
-       vfd->dev     = &btv->c.pci->dev;
-       vfd->release = video_device_release;
-       snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
-                btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
-                type, bttv_tvcards[btv->c.type].name);
-       return vfd;
-}
-
-static void bttv_unregister_video(struct bttv *btv)
-{
-       if (btv->video_dev) {
-               if (-1 != btv->video_dev->minor)
-                       video_unregister_device(btv->video_dev);
-               else
-                       video_device_release(btv->video_dev);
-               btv->video_dev = NULL;
-       }
-       if (btv->vbi_dev) {
-               if (-1 != btv->vbi_dev->minor)
-                       video_unregister_device(btv->vbi_dev);
-               else
-                       video_device_release(btv->vbi_dev);
-               btv->vbi_dev = NULL;
-       }
-       if (btv->radio_dev) {
-               if (-1 != btv->radio_dev->minor)
-                       video_unregister_device(btv->radio_dev);
-               else
-                       video_device_release(btv->radio_dev);
-               btv->radio_dev = NULL;
-       }
-}
-
-/* register video4linux devices */
-static int __devinit bttv_register_video(struct bttv *btv)
-{
-       if (no_overlay <= 0) {
-               bttv_video_template.type |= VID_TYPE_OVERLAY;
-       } else {
-               printk("bttv: Overlay support disabled.\n");
-       }
-
-       /* video */
-       btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
-       if (NULL == btv->video_dev)
-               goto err;
-       if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
-               goto err;
-       printk(KERN_INFO "bttv%d: registered device video%d\n",
-              btv->c.nr,btv->video_dev->minor & 0x1f);
-       video_device_create_file(btv->video_dev, &class_device_attr_card);
-
-       /* vbi */
-       btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
-       if (NULL == btv->vbi_dev)
-               goto err;
-       if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
-               goto err;
-       printk(KERN_INFO "bttv%d: registered device vbi%d\n",
-              btv->c.nr,btv->vbi_dev->minor & 0x1f);
-
-       if (!btv->has_radio)
-               return 0;
-       /* radio */
-       btv->radio_dev = vdev_init(btv, &radio_template, "radio");
-       if (NULL == btv->radio_dev)
-               goto err;
-       if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
-               goto err;
-       printk(KERN_INFO "bttv%d: registered device radio%d\n",
-              btv->c.nr,btv->radio_dev->minor & 0x1f);
-
-       /* all done */
-       return 0;
-
- err:
-       bttv_unregister_video(btv);
-       return -1;
-}
-
-
-/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
-/* response on cards with no firmware is not enabled by OF */
-static void pci_set_command(struct pci_dev *dev)
-{
-#if defined(__powerpc__)
-       unsigned int cmd;
-
-       pci_read_config_dword(dev, PCI_COMMAND, &cmd);
-       cmd = (cmd | PCI_COMMAND_MEMORY );
-       pci_write_config_dword(dev, PCI_COMMAND, cmd);
-#endif
-}
-
-static int __devinit bttv_probe(struct pci_dev *dev,
-                               const struct pci_device_id *pci_id)
-{
-       int result;
-       unsigned char lat;
-       struct bttv *btv;
-
-       if (bttv_num == BTTV_MAX)
-               return -ENOMEM;
-       printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
-       btv=&bttvs[bttv_num];
-       memset(btv,0,sizeof(*btv));
-       btv->c.nr  = bttv_num;
-       sprintf(btv->c.name,"bttv%d",btv->c.nr);
-
-       /* initialize structs / fill in defaults */
-       mutex_init(&btv->lock);
-       mutex_init(&btv->reslock);
-       spin_lock_init(&btv->s_lock);
-       spin_lock_init(&btv->gpio_lock);
-       init_waitqueue_head(&btv->gpioq);
-       init_waitqueue_head(&btv->i2c_queue);
-       INIT_LIST_HEAD(&btv->c.subs);
-       INIT_LIST_HEAD(&btv->capture);
-       INIT_LIST_HEAD(&btv->vcapture);
-       v4l2_prio_init(&btv->prio);
-
-       init_timer(&btv->timeout);
-       btv->timeout.function = bttv_irq_timeout;
-       btv->timeout.data     = (unsigned long)btv;
-
-       btv->i2c_rc = -1;
-       btv->tuner_type  = UNSET;
-       btv->new_input   = UNSET;
-       btv->has_radio=radio[btv->c.nr];
-
-       /* pci stuff (init, get irq/mmio, ... */
-       btv->c.pci = dev;
-       btv->id  = dev->device;
-       if (pci_enable_device(dev)) {
-               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
-                      btv->c.nr);
-               return -EIO;
-       }
-       if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
-               printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
-                      btv->c.nr);
-               return -EIO;
-       }
-       if (!request_mem_region(pci_resource_start(dev,0),
-                               pci_resource_len(dev,0),
-                               btv->c.name)) {
-               printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
-                      btv->c.nr, pci_resource_start(dev,0));
-               return -EBUSY;
-       }
-       pci_set_master(dev);
-       pci_set_command(dev);
-       pci_set_drvdata(dev,btv);
-
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
-              bttv_num,btv->id, btv->revision, pci_name(dev));
-       printk("irq: %d, latency: %d, mmio: 0x%lx\n",
-              btv->c.pci->irq, lat, pci_resource_start(dev,0));
-       schedule();
-
-       btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
-       if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
-               printk("bttv%d: ioremap() failed\n", btv->c.nr);
-               result = -EIO;
-               goto fail1;
-       }
-
-       /* identify card */
-       bttv_idcard(btv);
-
-       /* disable irqs, register irq handler */
-       btwrite(0, BT848_INT_MASK);
-       result = request_irq(btv->c.pci->irq, bttv_irq,
-                            SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
-       if (result < 0) {
-               printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
-                      bttv_num,btv->c.pci->irq);
-               goto fail1;
-       }
-
-       if (0 != bttv_handle_chipset(btv)) {
-               result = -EIO;
-               goto fail2;
-       }
-
-       /* init options from insmod args */
-       btv->opt_combfilter = combfilter;
-       btv->opt_lumafilter = lumafilter;
-       btv->opt_automute   = automute;
-       btv->opt_chroma_agc = chroma_agc;
-       btv->opt_adc_crush  = adc_crush;
-       btv->opt_vcr_hack   = vcr_hack;
-       btv->opt_whitecrush_upper  = whitecrush_upper;
-       btv->opt_whitecrush_lower  = whitecrush_lower;
-       btv->opt_uv_ratio   = uv_ratio;
-       btv->opt_full_luma_range   = full_luma_range;
-       btv->opt_coring     = coring;
-
-       /* fill struct bttv with some useful defaults */
-       btv->init.btv         = btv;
-       btv->init.ov.w.width  = 320;
-       btv->init.ov.w.height = 240;
-       btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
-       btv->init.width       = 320;
-       btv->init.height      = 240;
-       btv->init.lines       = 16;
-       btv->input = 0;
-
-       /* initialize hardware */
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"pre-init");
-
-       bttv_risc_init_main(btv);
-       init_bt848(btv);
-
-       /* gpio */
-       btwrite(0x00, BT848_GPIO_REG_INP);
-       btwrite(0x00, BT848_GPIO_OUT_EN);
-       if (bttv_verbose)
-               bttv_gpio_tracking(btv,"init");
-
-       /* needs to be done before i2c is registered */
-       bttv_init_card1(btv);
-
-       /* register i2c + gpio */
-       init_bttv_i2c(btv);
-
-       /* some card-specific stuff (needs working i2c) */
-       bttv_init_card2(btv);
-       init_irqreg(btv);
-
-       /* register video4linux + input */
-       if (!bttv_tvcards[btv->c.type].no_video) {
-               bttv_register_video(btv);
-               bt848_bright(btv,32768);
-               bt848_contrast(btv,32768);
-               bt848_hue(btv,32768);
-               bt848_sat(btv,32768);
-               audio_mux(btv,AUDIO_MUTE);
-               set_input(btv,0);
-       }
-
-       /* add subdevices */
-       if (bttv_tvcards[btv->c.type].has_dvb)
-               bttv_sub_add_device(&btv->c, "dvb");
-
-       bttv_input_init(btv);
-
-       /* everything is fine */
-       bttv_num++;
-       return 0;
-
- fail2:
-       free_irq(btv->c.pci->irq,btv);
-
- fail1:
-       if (btv->bt848_mmio)
-               iounmap(btv->bt848_mmio);
-       release_mem_region(pci_resource_start(btv->c.pci,0),
-                          pci_resource_len(btv->c.pci,0));
-       pci_set_drvdata(dev,NULL);
-       return result;
-}
-
-static void __devexit bttv_remove(struct pci_dev *pci_dev)
-{
-       struct bttv *btv = pci_get_drvdata(pci_dev);
-
-       if (bttv_verbose)
-               printk("bttv%d: unloading\n",btv->c.nr);
-
-       /* shutdown everything (DMA+IRQs) */
-       btand(~15, BT848_GPIO_DMA_CTL);
-       btwrite(0, BT848_INT_MASK);
-       btwrite(~0x0, BT848_INT_STAT);
-       btwrite(0x0, BT848_GPIO_OUT_EN);
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"cleanup");
-
-       /* tell gpio modules we are leaving ... */
-       btv->shutdown=1;
-       wake_up(&btv->gpioq);
-       bttv_input_fini(btv);
-       bttv_sub_del_devices(&btv->c);
-
-       /* unregister i2c_bus + input */
-       fini_bttv_i2c(btv);
-
-       /* unregister video4linux */
-       bttv_unregister_video(btv);
-
-       /* free allocated memory */
-       btcx_riscmem_free(btv->c.pci,&btv->main);
-
-       /* free ressources */
-       free_irq(btv->c.pci->irq,btv);
-       iounmap(btv->bt848_mmio);
-       release_mem_region(pci_resource_start(btv->c.pci,0),
-                          pci_resource_len(btv->c.pci,0));
-
-       pci_set_drvdata(pci_dev, NULL);
-       return;
-}
-
-static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
-{
-       struct bttv *btv = pci_get_drvdata(pci_dev);
-       struct bttv_buffer_set idle;
-       unsigned long flags;
-
-       dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
-
-       /* stop dma + irqs */
-       spin_lock_irqsave(&btv->s_lock,flags);
-       memset(&idle, 0, sizeof(idle));
-       btv->state.video = btv->curr;
-       btv->state.vbi   = btv->cvbi;
-       btv->state.loop_irq = btv->loop_irq;
-       btv->curr = idle;
-       btv->loop_irq = 0;
-       bttv_buffer_activate_video(btv, &idle);
-       bttv_buffer_activate_vbi(btv, NULL);
-       bttv_set_dma(btv, 0);
-       btwrite(0, BT848_INT_MASK);
-       spin_unlock_irqrestore(&btv->s_lock,flags);
-
-       /* save bt878 state */
-       btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
-       btv->state.gpio_data   = gpio_read();
-
-       /* save pci state */
-       pci_save_state(pci_dev);
-       if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
-               pci_disable_device(pci_dev);
-               btv->state.disabled = 1;
-       }
-       return 0;
-}
-
-static int bttv_resume(struct pci_dev *pci_dev)
-{
-       struct bttv *btv = pci_get_drvdata(pci_dev);
-       unsigned long flags;
-       int err;
-
-       dprintk("bttv%d: resume\n", btv->c.nr);
-
-       /* restore pci state */
-       if (btv->state.disabled) {
-               err=pci_enable_device(pci_dev);
-               if (err) {
-                       printk(KERN_WARNING "bttv%d: Can't enable device.\n",
-                                                               btv->c.nr);
-                       return err;
-               }
-               btv->state.disabled = 0;
-       }
-       err=pci_set_power_state(pci_dev, PCI_D0);
-       if (err) {
-               pci_disable_device(pci_dev);
-               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
-                                                       btv->c.nr);
-               btv->state.disabled = 1;
-               return err;
-       }
-
-       pci_restore_state(pci_dev);
-
-       /* restore bt878 state */
-       bttv_reinit_bt848(btv);
-       gpio_inout(0xffffff, btv->state.gpio_enable);
-       gpio_write(btv->state.gpio_data);
-
-       /* restart dma */
-       spin_lock_irqsave(&btv->s_lock,flags);
-       btv->curr = btv->state.video;
-       btv->cvbi = btv->state.vbi;
-       btv->loop_irq = btv->state.loop_irq;
-       bttv_buffer_activate_video(btv, &btv->curr);
-       bttv_buffer_activate_vbi(btv, btv->cvbi);
-       bttv_set_dma(btv, 0);
-       spin_unlock_irqrestore(&btv->s_lock,flags);
-       return 0;
-}
-
-static struct pci_device_id bttv_pci_tbl[] = {
-       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
-
-static struct pci_driver bttv_pci_driver = {
-       .name     = "bttv",
-       .id_table = bttv_pci_tbl,
-       .probe    = bttv_probe,
-       .remove   = __devexit_p(bttv_remove),
-       .suspend  = bttv_suspend,
-       .resume   = bttv_resume,
-};
-
-static int bttv_init_module(void)
-{
-       bttv_num = 0;
-
-       printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
-              (BTTV_VERSION_CODE >> 16) & 0xff,
-              (BTTV_VERSION_CODE >> 8) & 0xff,
-              BTTV_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
-       if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
-               gbuffers = 2;
-       if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
-               gbufsize = BTTV_MAX_FBUF;
-       gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
-       if (bttv_verbose)
-               printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
-                      gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
-
-       bttv_check_chipset();
-
-       bus_register(&bttv_sub_bus_type);
-       return pci_register_driver(&bttv_pci_driver);
-}
-
-static void bttv_cleanup_module(void)
-{
-       pci_unregister_driver(&bttv_pci_driver);
-       bus_unregister(&bttv_sub_bus_type);
-       return;
-}
-
-module_init(bttv_init_module);
-module_exit(bttv_cleanup_module);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
deleted file mode 100644 (file)
index c4d5e2b..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
-
-    bttv-gpio.c  --  gpio sub drivers
-
-    sysfs-based sub driver interface for bttv
-    mainly intented for gpio access
-
-
-    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                          & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <asm/io.h>
-
-#include "bttvp.h"
-
-/* ----------------------------------------------------------------------- */
-/* internal: the bttv "bus"                                                */
-
-static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
-       int len = strlen(sub->wanted);
-
-       if (0 == strncmp(dev->bus_id, sub->wanted, len))
-               return 1;
-       return 0;
-}
-
-static int bttv_sub_probe(struct device *dev)
-{
-       struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
-       struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
-
-       return sub->probe ? sub->probe(sdev) : -ENODEV;
-}
-
-static int bttv_sub_remove(struct device *dev)
-{
-       struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
-       struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
-
-       if (sub->remove)
-               sub->remove(sdev);
-       return 0;
-}
-
-struct bus_type bttv_sub_bus_type = {
-       .name   = "bttv-sub",
-       .match  = &bttv_sub_bus_match,
-       .probe  = bttv_sub_probe,
-       .remove = bttv_sub_remove,
-};
-EXPORT_SYMBOL(bttv_sub_bus_type);
-
-static void release_sub_device(struct device *dev)
-{
-       struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
-       kfree(sub);
-}
-
-int bttv_sub_add_device(struct bttv_core *core, char *name)
-{
-       struct bttv_sub_device *sub;
-       int err;
-
-       sub = kzalloc(sizeof(*sub),GFP_KERNEL);
-       if (NULL == sub)
-               return -ENOMEM;
-
-       sub->core        = core;
-       sub->dev.parent  = &core->pci->dev;
-       sub->dev.bus     = &bttv_sub_bus_type;
-       sub->dev.release = release_sub_device;
-       snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
-                name, core->nr);
-
-       err = device_register(&sub->dev);
-       if (0 != err) {
-               kfree(sub);
-               return err;
-       }
-       printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
-       list_add_tail(&sub->list,&core->subs);
-       return 0;
-}
-
-int bttv_sub_del_devices(struct bttv_core *core)
-{
-       struct bttv_sub_device *sub;
-       struct list_head *item,*save;
-
-       list_for_each_safe(item,save,&core->subs) {
-               sub = list_entry(item,struct bttv_sub_device,list);
-               list_del(&sub->list);
-               device_unregister(&sub->dev);
-       }
-       return 0;
-}
-
-void bttv_gpio_irq(struct bttv_core *core)
-{
-       struct bttv_sub_driver *drv;
-       struct bttv_sub_device *dev;
-       struct list_head *item;
-
-       list_for_each(item,&core->subs) {
-               dev = list_entry(item,struct bttv_sub_device,list);
-               drv = to_bttv_sub_drv(dev->dev.driver);
-               if (drv && drv->gpio_irq)
-                       drv->gpio_irq(dev);
-       }
-}
-
-/* ----------------------------------------------------------------------- */
-/* external: sub-driver register/unregister                                */
-
-int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
-{
-       sub->drv.bus = &bttv_sub_bus_type;
-       snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
-       return driver_register(&sub->drv);
-}
-EXPORT_SYMBOL(bttv_sub_register);
-
-int bttv_sub_unregister(struct bttv_sub_driver *sub)
-{
-       driver_unregister(&sub->drv);
-       return 0;
-}
-EXPORT_SYMBOL(bttv_sub_unregister);
-
-/* ----------------------------------------------------------------------- */
-/* external: gpio access functions                                         */
-
-void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
-{
-       struct bttv *btv = container_of(core, struct bttv, c);
-       unsigned long flags;
-       u32 data;
-
-       spin_lock_irqsave(&btv->gpio_lock,flags);
-       data = btread(BT848_GPIO_OUT_EN);
-       data = data & ~mask;
-       data = data | (mask & outbits);
-       btwrite(data,BT848_GPIO_OUT_EN);
-       spin_unlock_irqrestore(&btv->gpio_lock,flags);
-}
-EXPORT_SYMBOL(bttv_gpio_inout);
-
-u32 bttv_gpio_read(struct bttv_core *core)
-{
-       struct bttv *btv = container_of(core, struct bttv, c);
-       u32 value;
-
-       value = btread(BT848_GPIO_DATA);
-       return value;
-}
-EXPORT_SYMBOL(bttv_gpio_read);
-
-void bttv_gpio_write(struct bttv_core *core, u32 value)
-{
-       struct bttv *btv = container_of(core, struct bttv, c);
-
-       btwrite(value,BT848_GPIO_DATA);
-}
-EXPORT_SYMBOL(bttv_gpio_write);
-
-void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
-{
-       struct bttv *btv = container_of(core, struct bttv, c);
-       unsigned long flags;
-       u32 data;
-
-       spin_lock_irqsave(&btv->gpio_lock,flags);
-       data = btread(BT848_GPIO_DATA);
-       data = data & ~mask;
-       data = data | (mask & bits);
-       btwrite(data,BT848_GPIO_DATA);
-       spin_unlock_irqrestore(&btv->gpio_lock,flags);
-}
-EXPORT_SYMBOL(bttv_gpio_bits);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
deleted file mode 100644 (file)
index 614c120..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
-
-    bttv-i2c.c  --  all the i2c code is here
-
-    bttv - Bt848 frame grabber driver
-
-    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                          & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include "bttvp.h"
-#include <media/v4l2-common.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
-
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template;
-static struct i2c_adapter bttv_i2c_adap_sw_template;
-static struct i2c_adapter bttv_i2c_adap_hw_template;
-static struct i2c_client bttv_i2c_client_template;
-
-static int attach_inform(struct i2c_client *client);
-
-static int i2c_debug;
-static int i2c_hw;
-static int i2c_scan;
-module_param(i2c_debug, int, 0644);
-module_param(i2c_hw,    int, 0444);
-module_param(i2c_scan,  int, 0444);
-MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
-
-/* ----------------------------------------------------------------------- */
-/* I2C functions - bitbanging adapter (software i2c)                       */
-
-static void bttv_bit_setscl(void *data, int state)
-{
-       struct bttv *btv = (struct bttv*)data;
-
-       if (state)
-               btv->i2c_state |= 0x02;
-       else
-               btv->i2c_state &= ~0x02;
-       btwrite(btv->i2c_state, BT848_I2C);
-       btread(BT848_I2C);
-}
-
-static void bttv_bit_setsda(void *data, int state)
-{
-       struct bttv *btv = (struct bttv*)data;
-
-       if (state)
-               btv->i2c_state |= 0x01;
-       else
-               btv->i2c_state &= ~0x01;
-       btwrite(btv->i2c_state, BT848_I2C);
-       btread(BT848_I2C);
-}
-
-static int bttv_bit_getscl(void *data)
-{
-       struct bttv *btv = (struct bttv*)data;
-       int state;
-
-       state = btread(BT848_I2C) & 0x02 ? 1 : 0;
-       return state;
-}
-
-static int bttv_bit_getsda(void *data)
-{
-       struct bttv *btv = (struct bttv*)data;
-       int state;
-
-       state = btread(BT848_I2C) & 0x01;
-       return state;
-}
-
-static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
-       .setsda  = bttv_bit_setsda,
-       .setscl  = bttv_bit_setscl,
-       .getsda  = bttv_bit_getsda,
-       .getscl  = bttv_bit_getscl,
-       .udelay  = 16,
-       .mdelay  = 10,
-       .timeout = 200,
-};
-
-static struct i2c_adapter bttv_i2c_adap_sw_template = {
-       .owner             = THIS_MODULE,
-       .class             = I2C_CLASS_TV_ANALOG,
-       .name              = "bttv",
-       .id                = I2C_HW_B_BT848,
-       .client_register   = attach_inform,
-};
-
-/* ----------------------------------------------------------------------- */
-/* I2C functions - hardware i2c                                            */
-
-static int algo_control(struct i2c_adapter *adapter,
-                       unsigned int cmd, unsigned long arg)
-{
-       return 0;
-}
-
-static u32 functionality(struct i2c_adapter *adap)
-{
-       return I2C_FUNC_SMBUS_EMUL;
-}
-
-static int
-bttv_i2c_wait_done(struct bttv *btv)
-{
-       int rc = 0;
-
-       /* timeout */
-       if (wait_event_interruptible_timeout(btv->i2c_queue,
-               btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
-
-       rc = -EIO;
-
-       if (btv->i2c_done & BT848_INT_RACK)
-               rc = 1;
-       btv->i2c_done = 0;
-       return rc;
-}
-
-#define I2C_HW (BT878_I2C_MODE  | BT848_I2C_SYNC |\
-               BT848_I2C_SCL | BT848_I2C_SDA)
-
-static int
-bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
-{
-       u32 xmit;
-       int retval,cnt;
-
-       /* sanity checks */
-       if (0 == msg->len)
-               return -EINVAL;
-
-       /* start, address + first byte */
-       xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW;
-       if (msg->len > 1 || !last)
-               xmit |= BT878_I2C_NOSTOP;
-       btwrite(xmit, BT848_I2C);
-       retval = bttv_i2c_wait_done(btv);
-       if (retval < 0)
-               goto err;
-       if (retval == 0)
-               goto eio;
-       if (i2c_debug) {
-               printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
-               if (!(xmit & BT878_I2C_NOSTOP))
-                       printk(" >\n");
-       }
-
-       for (cnt = 1; cnt < msg->len; cnt++ ) {
-               /* following bytes */
-               xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART;
-               if (cnt < msg->len-1 || !last)
-                       xmit |= BT878_I2C_NOSTOP;
-               btwrite(xmit, BT848_I2C);
-               retval = bttv_i2c_wait_done(btv);
-               if (retval < 0)
-                       goto err;
-               if (retval == 0)
-                       goto eio;
-               if (i2c_debug) {
-                       printk(" %02x", msg->buf[cnt]);
-                       if (!(xmit & BT878_I2C_NOSTOP))
-                               printk(" >\n");
-               }
-       }
-       return msg->len;
-
- eio:
-       retval = -EIO;
- err:
-       if (i2c_debug)
-               printk(" ERR: %d\n",retval);
-       return retval;
-}
-
-static int
-bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
-{
-       u32 xmit;
-       u32 cnt;
-       int retval;
-
-       for(cnt = 0; cnt < msg->len; cnt++) {
-               xmit = (msg->addr << 25) | (1 << 24) | I2C_HW;
-               if (cnt < msg->len-1)
-                       xmit |= BT848_I2C_W3B;
-               if (cnt < msg->len-1 || !last)
-                       xmit |= BT878_I2C_NOSTOP;
-               if (cnt)
-                       xmit |= BT878_I2C_NOSTART;
-               btwrite(xmit, BT848_I2C);
-               retval = bttv_i2c_wait_done(btv);
-               if (retval < 0)
-                       goto err;
-               if (retval == 0)
-                       goto eio;
-               msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff;
-               if (i2c_debug) {
-                       if (!(xmit & BT878_I2C_NOSTART))
-                               printk(" <R %02x", (msg->addr << 1) +1);
-                       printk(" =%02x", msg->buf[cnt]);
-                       if (!(xmit & BT878_I2C_NOSTOP))
-                               printk(" >\n");
-               }
-       }
-       return msg->len;
-
- eio:
-       retval = -EIO;
- err:
-       if (i2c_debug)
-               printk(" ERR: %d\n",retval);
-       return retval;
-}
-
-static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
-{
-       struct bttv *btv = i2c_get_adapdata(i2c_adap);
-       int retval = 0;
-       int i;
-
-       if (i2c_debug)
-               printk("bt-i2c:");
-       btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT);
-       for (i = 0 ; i < num; i++) {
-               if (msgs[i].flags & I2C_M_RD) {
-                       /* read */
-                       retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num);
-                       if (retval < 0)
-                               goto err;
-               } else {
-                       /* write */
-                       retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num);
-                       if (retval < 0)
-                               goto err;
-               }
-       }
-       return num;
-
- err:
-       return retval;
-}
-
-static struct i2c_algorithm bttv_algo = {
-       .master_xfer   = bttv_i2c_xfer,
-       .algo_control  = algo_control,
-       .functionality = functionality,
-};
-
-static struct i2c_adapter bttv_i2c_adap_hw_template = {
-       .owner             = THIS_MODULE,
-       .class         = I2C_CLASS_TV_ANALOG,
-       .name          = "bt878",
-       .id            = I2C_HW_B_BT848 /* FIXME */,
-       .algo          = &bttv_algo,
-       .client_register = attach_inform,
-};
-
-/* ----------------------------------------------------------------------- */
-/* I2C functions - common stuff                                            */
-
-static int attach_inform(struct i2c_client *client)
-{
-       struct bttv *btv = i2c_get_adapdata(client->adapter);
-       int addr=ADDR_UNSET;
-
-
-       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
-               addr = bttv_tvcards[btv->c.type].tuner_addr;
-
-
-       if (bttv_debug)
-               printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
-                       btv->c.nr, client->driver->driver.name, client->addr,
-                       client->name);
-       if (!client->driver->command)
-               return 0;
-
-       if (btv->tuner_type != UNSET) {
-               struct tuner_setup tun_setup;
-
-               if ((addr==ADDR_UNSET) ||
-                               (addr==client->addr)) {
-
-                       tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
-                       tun_setup.type = btv->tuner_type;
-                       tun_setup.addr = addr;
-                       bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
-               }
-
-       }
-
-       return 0;
-}
-
-void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
-{
-       if (0 != btv->i2c_rc)
-               return;
-       i2c_clients_command(&btv->c.i2c_adap, cmd, arg);
-}
-
-static struct i2c_client bttv_i2c_client_template = {
-       .name   = "bttv internal",
-};
-
-
-/* read I2C */
-int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
-{
-       unsigned char buffer = 0;
-
-       if (0 != btv->i2c_rc)
-               return -1;
-       if (bttv_verbose && NULL != probe_for)
-               printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
-                      btv->c.nr,probe_for,addr);
-       btv->i2c_client.addr = addr >> 1;
-       if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
-               if (NULL != probe_for) {
-                       if (bttv_verbose)
-                               printk("not found\n");
-               } else
-                       printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
-                              btv->c.nr,addr);
-               return -1;
-       }
-       if (bttv_verbose && NULL != probe_for)
-               printk("found\n");
-       return buffer;
-}
-
-/* write I2C */
-int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
-                   unsigned char b2, int both)
-{
-       unsigned char buffer[2];
-       int bytes = both ? 2 : 1;
-
-       if (0 != btv->i2c_rc)
-               return -1;
-       btv->i2c_client.addr = addr >> 1;
-       buffer[0] = b1;
-       buffer[1] = b2;
-       if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
-               return -1;
-       return 0;
-}
-
-/* read EEPROM content */
-void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
-{
-       memset(eedata, 0, 256);
-       if (0 != btv->i2c_rc)
-               return;
-       btv->i2c_client.addr = addr >> 1;
-       tveeprom_read(&btv->i2c_client, eedata, 256);
-}
-
-static char *i2c_devs[128] = {
-       [ 0x1c >> 1 ] = "lgdt330x",
-       [ 0x30 >> 1 ] = "IR (hauppauge)",
-       [ 0x80 >> 1 ] = "msp34xx",
-       [ 0x86 >> 1 ] = "tda9887",
-       [ 0xa0 >> 1 ] = "eeprom",
-       [ 0xc0 >> 1 ] = "tuner (analog)",
-       [ 0xc2 >> 1 ] = "tuner (analog)",
-};
-
-static void do_i2c_scan(char *name, struct i2c_client *c)
-{
-       unsigned char buf;
-       int i,rc;
-
-       for (i = 0; i < 128; i++) {
-               c->addr = i;
-               rc = i2c_master_recv(c,&buf,0);
-               if (rc < 0)
-                       continue;
-               printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
-                      name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
-       }
-}
-
-/* init + register i2c algo-bit adapter */
-int __devinit init_bttv_i2c(struct bttv *btv)
-{
-       memcpy(&btv->i2c_client, &bttv_i2c_client_template,
-              sizeof(bttv_i2c_client_template));
-
-       if (i2c_hw)
-               btv->use_i2c_hw = 1;
-       if (btv->use_i2c_hw) {
-               /* bt878 */
-               memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_hw_template,
-                      sizeof(bttv_i2c_adap_hw_template));
-       } else {
-               /* bt848 */
-               memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
-                      sizeof(bttv_i2c_adap_sw_template));
-               memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
-                      sizeof(bttv_i2c_algo_bit_template));
-               btv->i2c_algo.data = btv;
-               btv->c.i2c_adap.algo_data = &btv->i2c_algo;
-       }
-
-       btv->c.i2c_adap.dev.parent = &btv->c.pci->dev;
-       snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name),
-                "bt%d #%d [%s]", btv->id, btv->c.nr,
-                btv->use_i2c_hw ? "hw" : "sw");
-
-       i2c_set_adapdata(&btv->c.i2c_adap, btv);
-       btv->i2c_client.adapter = &btv->c.i2c_adap;
-
-       if (bttv_tvcards[btv->c.type].no_video)
-               btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG;
-       if (bttv_tvcards[btv->c.type].has_dvb)
-               btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
-
-       if (btv->use_i2c_hw) {
-               btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap);
-       } else {
-               bttv_bit_setscl(btv,1);
-               bttv_bit_setsda(btv,1);
-               btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap);
-       }
-       if (0 == btv->i2c_rc && i2c_scan)
-               do_i2c_scan(btv->c.name,&btv->i2c_client);
-       return btv->i2c_rc;
-}
-
-int __devexit fini_bttv_i2c(struct bttv *btv)
-{
-       if (0 != btv->i2c_rc)
-               return 0;
-
-       if (btv->use_i2c_hw) {
-               return i2c_del_adapter(&btv->c.i2c_adap);
-       } else {
-               return i2c_bit_del_bus(&btv->c.i2c_adap);
-       }
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c
deleted file mode 100644 (file)
index 19b564a..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
-
-    bttv-if.c  --  old gpio interface to other kernel modules
-                  don't use in new code, will go away in 2.7
-                  have a look at bttv-gpio.c instead.
-
-    bttv - Bt848 frame grabber driver
-
-    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                          & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-#include "bttvp.h"
-
-EXPORT_SYMBOL(bttv_get_cardinfo);
-EXPORT_SYMBOL(bttv_get_pcidev);
-EXPORT_SYMBOL(bttv_get_id);
-EXPORT_SYMBOL(bttv_gpio_enable);
-EXPORT_SYMBOL(bttv_read_gpio);
-EXPORT_SYMBOL(bttv_write_gpio);
-EXPORT_SYMBOL(bttv_get_gpio_queue);
-EXPORT_SYMBOL(bttv_i2c_call);
-
-/* ----------------------------------------------------------------------- */
-/* Exported functions - for other modules which want to access the         */
-/*                      gpio ports (IR for example)                        */
-/*                      see bttv.h for comments                            */
-
-int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid)
-{
-       printk("The bttv_* interface is obsolete and will go away,\n"
-              "please use the new, sysfs based interface instead.\n");
-       if (card >= bttv_num) {
-               return -1;
-       }
-       *type   = bttvs[card].c.type;
-       *cardid = bttvs[card].cardid;
-       return 0;
-}
-
-struct pci_dev* bttv_get_pcidev(unsigned int card)
-{
-       if (card >= bttv_num)
-               return NULL;
-       return bttvs[card].c.pci;
-}
-
-int bttv_get_id(unsigned int card)
-{
-       printk("The bttv_* interface is obsolete and will go away,\n"
-              "please use the new, sysfs based interface instead.\n");
-       if (card >= bttv_num) {
-               return -1;
-       }
-       return bttvs[card].c.type;
-}
-
-
-int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
-{
-       struct bttv *btv;
-
-       if (card >= bttv_num) {
-               return -EINVAL;
-       }
-
-       btv = &bttvs[card];
-       gpio_inout(mask,data);
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"extern enable");
-       return 0;
-}
-
-int bttv_read_gpio(unsigned int card, unsigned long *data)
-{
-       struct bttv *btv;
-
-       if (card >= bttv_num) {
-               return -EINVAL;
-       }
-
-       btv = &bttvs[card];
-
-       if(btv->shutdown) {
-               return -ENODEV;
-       }
-
-/* prior setting BT848_GPIO_REG_INP is (probably) not needed
-   because we set direct input on init */
-       *data = gpio_read();
-       return 0;
-}
-
-int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
-{
-       struct bttv *btv;
-
-       if (card >= bttv_num) {
-               return -EINVAL;
-       }
-
-       btv = &bttvs[card];
-
-/* prior setting BT848_GPIO_REG_INP is (probably) not needed
-   because direct input is set on init */
-       gpio_bits(mask,data);
-       if (bttv_gpio)
-               bttv_gpio_tracking(btv,"extern write");
-       return 0;
-}
-
-wait_queue_head_t* bttv_get_gpio_queue(unsigned int card)
-{
-       struct bttv *btv;
-
-       if (card >= bttv_num) {
-               return NULL;
-       }
-
-       btv = &bttvs[card];
-       if (bttvs[card].shutdown) {
-               return NULL;
-       }
-       return &btv->gpioq;
-}
-
-void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
-{
-       if (card >= bttv_num)
-               return;
-       bttv_call_i2c_clients(&bttvs[card], cmd, arg);
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c
deleted file mode 100644 (file)
index 69efa0e..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- *
- * Copyright (c) 2003 Gerd Knorr
- * Copyright (c) 2003 Pavel Machek
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-
-#include "bttv.h"
-#include "bttvp.h"
-
-
-static int debug;
-module_param(debug, int, 0644);    /* debug level (0,1,2) */
-static int repeat_delay = 500;
-module_param(repeat_delay, int, 0644);
-static int repeat_period = 33;
-module_param(repeat_period, int, 0644);
-
-#define DEVNAME "bttv-input"
-
-/* ---------------------------------------------------------------------- */
-
-static void ir_handle_key(struct bttv *btv)
-{
-       struct bttv_ir *ir = btv->remote;
-       u32 gpio,data;
-
-       /* read gpio value */
-       gpio = bttv_gpio_read(&btv->c);
-       if (ir->polling) {
-               if (ir->last_gpio == gpio)
-                       return;
-               ir->last_gpio = gpio;
-       }
-
-       /* extract data */
-       data = ir_extract_bits(gpio, ir->mask_keycode);
-       dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n",
-               gpio, data,
-               ir->polling               ? "poll"  : "irq",
-               (gpio & ir->mask_keydown) ? " down" : "",
-               (gpio & ir->mask_keyup)   ? " up"   : "");
-
-       if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
-           (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
-               ir_input_keydown(ir->dev,&ir->ir,data,data);
-       } else {
-               ir_input_nokey(ir->dev,&ir->ir);
-       }
-
-}
-
-void bttv_input_irq(struct bttv *btv)
-{
-       struct bttv_ir *ir = btv->remote;
-
-       if (!ir->polling)
-               ir_handle_key(btv);
-}
-
-static void bttv_input_timer(unsigned long data)
-{
-       struct bttv *btv = (struct bttv*)data;
-       struct bttv_ir *ir = btv->remote;
-       unsigned long timeout;
-
-       ir_handle_key(btv);
-       timeout = jiffies + (ir->polling * HZ / 1000);
-       mod_timer(&ir->timer, timeout);
-}
-
-/* ---------------------------------------------------------------*/
-
-static int rc5_remote_gap = 885;
-module_param(rc5_remote_gap, int, 0644);
-static int rc5_key_timeout = 200;
-module_param(rc5_key_timeout, int, 0644);
-
-#define RC5_START(x)   (((x)>>12)&3)
-#define RC5_TOGGLE(x)  (((x)>>11)&1)
-#define RC5_ADDR(x)    (((x)>>6)&31)
-#define RC5_INSTR(x)   ((x)&63)
-
-/* decode raw bit pattern to RC5 code */
-static u32 rc5_decode(unsigned int code)
-{
-       unsigned int org_code = code;
-       unsigned int pair;
-       unsigned int rc5 = 0;
-       int i;
-
-       code = (code << 1) | 1;
-       for (i = 0; i < 14; ++i) {
-               pair = code & 0x3;
-               code >>= 2;
-
-               rc5 <<= 1;
-               switch (pair) {
-               case 0:
-               case 2:
-                       break;
-               case 1:
-                       rc5 |= 1;
-                       break;
-               case 3:
-                       dprintk(KERN_WARNING "bad code: %x\n", org_code);
-                       return 0;
-               }
-       }
-       dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
-               "instr=%x\n", rc5, org_code, RC5_START(rc5),
-               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
-       return rc5;
-}
-
-static int bttv_rc5_irq(struct bttv *btv)
-{
-       struct bttv_ir *ir = btv->remote;
-       struct timeval tv;
-       u32 gpio;
-       u32 gap;
-       unsigned long current_jiffies, timeout;
-
-       /* read gpio port */
-       gpio = bttv_gpio_read(&btv->c);
-
-       /* remote IRQ? */
-       if (!(gpio & 0x20))
-               return 0;
-
-       /* get time of bit */
-       current_jiffies = jiffies;
-       do_gettimeofday(&tv);
-
-       /* avoid overflow with gap >1s */
-       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
-               gap = 200000;
-       } else {
-               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
-                   tv.tv_usec - ir->base_time.tv_usec;
-       }
-
-       /* active code => add bit */
-       if (ir->active) {
-               /* only if in the code (otherwise spurious IRQ or timer
-                  late) */
-               if (ir->last_bit < 28) {
-                       ir->last_bit = (gap - rc5_remote_gap / 2) /
-                           rc5_remote_gap;
-                       ir->code |= 1 << ir->last_bit;
-               }
-               /* starting new code */
-       } else {
-               ir->active = 1;
-               ir->code = 0;
-               ir->base_time = tv;
-               ir->last_bit = 0;
-
-               timeout = current_jiffies + (500 + 30 * HZ) / 1000;
-               mod_timer(&ir->timer_end, timeout);
-       }
-
-       /* toggle GPIO pin 4 to reset the irq */
-       bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
-       bttv_gpio_write(&btv->c, gpio | (1 << 4));
-       return 1;
-}
-
-
-static void bttv_rc5_timer_end(unsigned long data)
-{
-       struct bttv_ir *ir = (struct bttv_ir *)data;
-       struct timeval tv;
-       unsigned long current_jiffies, timeout;
-       u32 gap;
-
-       /* get time */
-       current_jiffies = jiffies;
-       do_gettimeofday(&tv);
-
-       /* avoid overflow with gap >1s */
-       if (tv.tv_sec - ir->base_time.tv_sec > 1) {
-               gap = 200000;
-       } else {
-               gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
-                   tv.tv_usec - ir->base_time.tv_usec;
-       }
-
-       /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
-       if (gap < 28000) {
-               dprintk(KERN_WARNING "spurious timer_end\n");
-               return;
-       }
-
-       ir->active = 0;
-       if (ir->last_bit < 20) {
-               /* ignore spurious codes (caused by light/other remotes) */
-               dprintk(KERN_WARNING "short code: %x\n", ir->code);
-       } else {
-               u32 rc5 = rc5_decode(ir->code);
-
-               /* two start bits? */
-               if (RC5_START(rc5) != 3) {
-                       dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
-
-                       /* right address? */
-               } else if (RC5_ADDR(rc5) == 0x0) {
-                       u32 toggle = RC5_TOGGLE(rc5);
-                       u32 instr = RC5_INSTR(rc5);
-
-                       /* Good code, decide if repeat/repress */
-                       if (toggle != RC5_TOGGLE(ir->last_rc5) ||
-                           instr != RC5_INSTR(ir->last_rc5)) {
-                               dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
-                                       toggle);
-                               ir_input_nokey(ir->dev, &ir->ir);
-                               ir_input_keydown(ir->dev, &ir->ir, instr,
-                                                instr);
-                       }
-
-                       /* Set/reset key-up timer */
-                       timeout = current_jiffies + (500 + rc5_key_timeout
-                                                    * HZ) / 1000;
-                       mod_timer(&ir->timer_keyup, timeout);
-
-                       /* Save code for repeat test */
-                       ir->last_rc5 = rc5;
-               }
-       }
-}
-
-static void bttv_rc5_timer_keyup(unsigned long data)
-{
-       struct bttv_ir *ir = (struct bttv_ir *)data;
-
-       dprintk(KERN_DEBUG "key released\n");
-       ir_input_nokey(ir->dev, &ir->ir);
-}
-
-/* ---------------------------------------------------------------------- */
-
-int bttv_input_init(struct bttv *btv)
-{
-       struct bttv_ir *ir;
-       IR_KEYTAB_TYPE *ir_codes = NULL;
-       struct input_dev *input_dev;
-       int ir_type = IR_TYPE_OTHER;
-
-       if (!btv->has_remote)
-               return -ENODEV;
-
-       ir = kzalloc(sizeof(*ir),GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ir || !input_dev) {
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENOMEM;
-       }
-       memset(ir,0,sizeof(*ir));
-
-       /* detect & configure */
-       switch (btv->c.type) {
-       case BTTV_BOARD_AVERMEDIA:
-       case BTTV_BOARD_AVPHONE98:
-       case BTTV_BOARD_AVERMEDIA98:
-               ir_codes         = ir_codes_avermedia;
-               ir->mask_keycode = 0xf88000;
-               ir->mask_keydown = 0x010000;
-               ir->polling      = 50; // ms
-               break;
-
-       case BTTV_BOARD_AVDVBT_761:
-       case BTTV_BOARD_AVDVBT_771:
-               ir_codes         = ir_codes_avermedia_dvbt;
-               ir->mask_keycode = 0x0f00c0;
-               ir->mask_keydown = 0x000020;
-               ir->polling      = 50; // ms
-               break;
-
-       case BTTV_BOARD_PXELVWPLTVPAK:
-               ir_codes         = ir_codes_pixelview;
-               ir->mask_keycode = 0x003e00;
-               ir->mask_keyup   = 0x010000;
-               ir->polling      = 50; // ms
-               break;
-       case BTTV_BOARD_PV_BT878P_9B:
-       case BTTV_BOARD_PV_BT878P_PLUS:
-               ir_codes         = ir_codes_pixelview;
-               ir->mask_keycode = 0x001f00;
-               ir->mask_keyup   = 0x008000;
-               ir->polling      = 50; // ms
-               break;
-
-       case BTTV_BOARD_WINFAST2000:
-               ir_codes         = ir_codes_winfast;
-               ir->mask_keycode = 0x1f8;
-               break;
-       case BTTV_BOARD_MAGICTVIEW061:
-       case BTTV_BOARD_MAGICTVIEW063:
-               ir_codes         = ir_codes_winfast;
-               ir->mask_keycode = 0x0008e000;
-               ir->mask_keydown = 0x00200000;
-               break;
-       case BTTV_BOARD_APAC_VIEWCOMP:
-               ir_codes         = ir_codes_apac_viewcomp;
-               ir->mask_keycode = 0x001f00;
-               ir->mask_keyup   = 0x008000;
-               ir->polling      = 50; // ms
-               break;
-       case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
-       case BTTV_BOARD_CONTVFMI:
-               ir_codes         = ir_codes_pixelview;
-               ir->mask_keycode = 0x001F00;
-               ir->mask_keyup   = 0x006000;
-               ir->polling      = 50; // ms
-               break;
-       case BTTV_BOARD_NEBULA_DIGITV:
-               ir_codes = ir_codes_nebula;
-               btv->custom_irq = bttv_rc5_irq;
-               ir->rc5_gpio = 1;
-               break;
-       case BTTV_BOARD_MACHTV_MAGICTV:
-               ir_codes         = ir_codes_apac_viewcomp;
-               ir->mask_keycode = 0x001F00;
-               ir->mask_keyup   = 0x004000;
-               ir->polling      = 50; /* ms */
-               break;
-       }
-       if (NULL == ir_codes) {
-               dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENODEV;
-       }
-
-       if (ir->rc5_gpio) {
-               u32 gpio;
-               /* enable remote irq */
-               bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
-               gpio = bttv_gpio_read(&btv->c);
-               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
-               bttv_gpio_write(&btv->c, gpio | (1 << 4));
-       } else {
-               /* init hardware-specific stuff */
-               bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0);
-       }
-
-       /* init input device */
-       ir->dev = input_dev;
-
-       snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
-                btv->c.type);
-       snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
-                pci_name(btv->c.pci));
-
-       ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
-       input_dev->name = ir->name;
-       input_dev->phys = ir->phys;
-       input_dev->id.bustype = BUS_PCI;
-       input_dev->id.version = 1;
-       if (btv->c.pci->subsystem_vendor) {
-               input_dev->id.vendor  = btv->c.pci->subsystem_vendor;
-               input_dev->id.product = btv->c.pci->subsystem_device;
-       } else {
-               input_dev->id.vendor  = btv->c.pci->vendor;
-               input_dev->id.product = btv->c.pci->device;
-       }
-       input_dev->cdev.dev = &btv->c.pci->dev;
-
-       btv->remote = ir;
-       if (ir->polling) {
-               init_timer(&ir->timer);
-               ir->timer.function = bttv_input_timer;
-               ir->timer.data     = (unsigned long)btv;
-               ir->timer.expires  = jiffies + HZ;
-               add_timer(&ir->timer);
-       } else if (ir->rc5_gpio) {
-               /* set timer_end for code completion */
-               init_timer(&ir->timer_end);
-               ir->timer_end.function = bttv_rc5_timer_end;
-               ir->timer_end.data = (unsigned long)ir;
-
-               init_timer(&ir->timer_keyup);
-               ir->timer_keyup.function = bttv_rc5_timer_keyup;
-               ir->timer_keyup.data = (unsigned long)ir;
-       }
-
-       /* all done */
-       input_register_device(btv->remote->dev);
-       printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
-
-       /* the remote isn't as bouncy as a keyboard */
-       ir->dev->rep[REP_DELAY] = repeat_delay;
-       ir->dev->rep[REP_PERIOD] = repeat_period;
-
-       return 0;
-}
-
-void bttv_input_fini(struct bttv *btv)
-{
-       if (btv->remote == NULL)
-               return;
-
-       if (btv->remote->polling) {
-               del_timer_sync(&btv->remote->timer);
-               flush_scheduled_work();
-       }
-
-
-       if (btv->remote->rc5_gpio) {
-               u32 gpio;
-
-               del_timer_sync(&btv->remote->timer_end);
-               flush_scheduled_work();
-
-               gpio = bttv_gpio_read(&btv->c);
-               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
-       }
-
-       input_unregister_device(btv->remote->dev);
-       kfree(btv->remote);
-       btv->remote = NULL;
-}
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
deleted file mode 100644 (file)
index 344f84e..0000000
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
-
-    bttv-risc.c  --  interfaces to other kernel modules
-
-    bttv risc code handling
-       - memory management
-       - generation
-
-    (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#include "bttvp.h"
-
-#define VCR_HACK_LINES 4
-
-/* ---------------------------------------------------------- */
-/* risc code generators                                       */
-
-int
-bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
-                struct scatterlist *sglist,
-                unsigned int offset, unsigned int bpl,
-                unsigned int padding, unsigned int lines)
-{
-       u32 instructions,line,todo;
-       struct scatterlist *sg;
-       u32 *rp;
-       int rc;
-
-       /* estimate risc mem: worst case is one write per page border +
-          one write per scan line + sync + jump (all 2 dwords).  padding
-          can cause next bpl to start close to a page border.  First DMA
-          region may be smaller than PAGE_SIZE */
-       instructions  = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
-       instructions += 2;
-       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
-               return rc;
-
-       /* sync instruction */
-       rp = risc->cpu;
-       *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
-       *(rp++) = cpu_to_le32(0);
-
-       /* scan lines */
-       sg = sglist;
-       for (line = 0; line < lines; line++) {
-               if ((btv->opt_vcr_hack) &&
-                   (line >= (lines - VCR_HACK_LINES)))
-                       continue;
-               while (offset && offset >= sg_dma_len(sg)) {
-                       offset -= sg_dma_len(sg);
-                       sg++;
-               }
-               if (bpl <= sg_dma_len(sg)-offset) {
-                       /* fits into current chunk */
-                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
-                                           BT848_RISC_EOL|bpl);
-                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                       offset+=bpl;
-               } else {
-                       /* scanline needs to be splitted */
-                       todo = bpl;
-                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
-                                           (sg_dma_len(sg)-offset));
-                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                       todo -= (sg_dma_len(sg)-offset);
-                       offset = 0;
-                       sg++;
-                       while (todo > sg_dma_len(sg)) {
-                               *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
-                                                   sg_dma_len(sg));
-                               *(rp++)=cpu_to_le32(sg_dma_address(sg));
-                               todo -= sg_dma_len(sg);
-                               sg++;
-                       }
-                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
-                                           todo);
-                       *(rp++)=cpu_to_le32(sg_dma_address(sg));
-                       offset += todo;
-               }
-               offset += padding;
-       }
-
-       /* save pointer to jmp instruction address */
-       risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
-       return 0;
-}
-
-static int
-bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
-                struct scatterlist *sglist,
-                unsigned int yoffset,  unsigned int ybpl,
-                unsigned int ypadding, unsigned int ylines,
-                unsigned int uoffset,  unsigned int voffset,
-                unsigned int hshift,   unsigned int vshift,
-                unsigned int cpadding)
-{
-       unsigned int instructions,line,todo,ylen,chroma;
-       u32 *rp,ri;
-       struct scatterlist *ysg;
-       struct scatterlist *usg;
-       struct scatterlist *vsg;
-       int topfield = (0 == yoffset);
-       int rc;
-
-       /* estimate risc mem: worst case is one write per page border +
-          one write per scan line (5 dwords)
-          plus sync + jump (2 dwords) */
-       instructions  = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
-       instructions += 2;
-       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
-               return rc;
-
-       /* sync instruction */
-       rp = risc->cpu;
-       *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
-       *(rp++) = cpu_to_le32(0);
-
-       /* scan lines */
-       ysg = sglist;
-       usg = sglist;
-       vsg = sglist;
-       for (line = 0; line < ylines; line++) {
-               if ((btv->opt_vcr_hack) &&
-                   (line >= (ylines - VCR_HACK_LINES)))
-                       continue;
-               switch (vshift) {
-               case 0:
-                       chroma = 1;
-                       break;
-               case 1:
-                       if (topfield)
-                               chroma = ((line & 1) == 0);
-                       else
-                               chroma = ((line & 1) == 1);
-                       break;
-               case 2:
-                       if (topfield)
-                               chroma = ((line & 3) == 0);
-                       else
-                               chroma = ((line & 3) == 2);
-                       break;
-               default:
-                       chroma = 0;
-                       break;
-               }
-
-               for (todo = ybpl; todo > 0; todo -= ylen) {
-                       /* go to next sg entry if needed */
-                       while (yoffset && yoffset >= sg_dma_len(ysg)) {
-                               yoffset -= sg_dma_len(ysg);
-                               ysg++;
-                       }
-                       while (uoffset && uoffset >= sg_dma_len(usg)) {
-                               uoffset -= sg_dma_len(usg);
-                               usg++;
-                       }
-                       while (voffset && voffset >= sg_dma_len(vsg)) {
-                               voffset -= sg_dma_len(vsg);
-                               vsg++;
-                       }
-
-                       /* calculate max number of bytes we can write */
-                       ylen = todo;
-                       if (yoffset + ylen > sg_dma_len(ysg))
-                               ylen = sg_dma_len(ysg) - yoffset;
-                       if (chroma) {
-                               if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
-                                       ylen = (sg_dma_len(usg) - uoffset) << hshift;
-                               if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
-                                       ylen = (sg_dma_len(vsg) - voffset) << hshift;
-                               ri = BT848_RISC_WRITE123;
-                       } else {
-                               ri = BT848_RISC_WRITE1S23;
-                       }
-                       if (ybpl == todo)
-                               ri |= BT848_RISC_SOL;
-                       if (ylen == todo)
-                               ri |= BT848_RISC_EOL;
-
-                       /* write risc instruction */
-                       *(rp++)=cpu_to_le32(ri | ylen);
-                       *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
-                                           (ylen >> hshift));
-                       *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
-                       yoffset += ylen;
-                       if (chroma) {
-                               *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
-                               uoffset += ylen >> hshift;
-                               *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
-                               voffset += ylen >> hshift;
-                       }
-               }
-               yoffset += ypadding;
-               if (chroma) {
-                       uoffset += cpadding;
-                       voffset += cpadding;
-               }
-       }
-
-       /* save pointer to jmp instruction address */
-       risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
-       return 0;
-}
-
-static int
-bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
-                 const struct bttv_format *fmt, struct bttv_overlay *ov,
-                 int skip_even, int skip_odd)
-{
-       int instructions,rc,line,maxy,start,end,skip,nskips;
-       struct btcx_skiplist *skips;
-       u32 *rp,ri,ra;
-       u32 addr;
-
-       /* skip list for window clipping */
-       if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
-               return -ENOMEM;
-
-       /* estimate risc mem: worst case is (clip+1) * lines instructions
-          + sync + jump (all 2 dwords) */
-       instructions  = (ov->nclips + 1) *
-               ((skip_even || skip_odd) ? ov->w.height>>1 :  ov->w.height);
-       instructions += 2;
-       if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) {
-               kfree(skips);
-               return rc;
-       }
-
-       /* sync instruction */
-       rp = risc->cpu;
-       *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
-       *(rp++) = cpu_to_le32(0);
-
-       addr  = (unsigned long)btv->fbuf.base;
-       addr += btv->fbuf.fmt.bytesperline * ov->w.top;
-       addr += (fmt->depth >> 3)          * ov->w.left;
-
-       /* scan lines */
-       for (maxy = -1, line = 0; line < ov->w.height;
-            line++, addr += btv->fbuf.fmt.bytesperline) {
-               if ((btv->opt_vcr_hack) &&
-                    (line >= (ov->w.height - VCR_HACK_LINES)))
-                       continue;
-               if ((line%2) == 0  &&  skip_even)
-                       continue;
-               if ((line%2) == 1  &&  skip_odd)
-                       continue;
-
-               /* calculate clipping */
-               if (line > maxy)
-                       btcx_calc_skips(line, ov->w.width, &maxy,
-                                       skips, &nskips, ov->clips, ov->nclips);
-               else
-                       nskips = 0;
-
-               /* write out risc code */
-               for (start = 0, skip = 0; start < ov->w.width; start = end) {
-                       if (skip >= nskips) {
-                               ri  = BT848_RISC_WRITE;
-                               end = ov->w.width;
-                       } else if (start < skips[skip].start) {
-                               ri  = BT848_RISC_WRITE;
-                               end = skips[skip].start;
-                       } else {
-                               ri  = BT848_RISC_SKIP;
-                               end = skips[skip].end;
-                               skip++;
-                       }
-                       if (BT848_RISC_WRITE == ri)
-                               ra = addr + (fmt->depth>>3)*start;
-                       else
-                               ra = 0;
-
-                       if (0 == start)
-                               ri |= BT848_RISC_SOL;
-                       if (ov->w.width == end)
-                               ri |= BT848_RISC_EOL;
-                       ri |= (fmt->depth>>3) * (end-start);
-
-                       *(rp++)=cpu_to_le32(ri);
-                       if (0 != ra)
-                               *(rp++)=cpu_to_le32(ra);
-               }
-       }
-
-       /* save pointer to jmp instruction address */
-       risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
-       kfree(skips);
-       return 0;
-}
-
-/* ---------------------------------------------------------- */
-
-static void
-bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
-             int width, int height, int interleaved, int norm)
-{
-       const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
-       u32 xsf, sr;
-       int vdelay;
-
-       int swidth       = tvnorm->swidth;
-       int totalwidth   = tvnorm->totalwidth;
-       int scaledtwidth = tvnorm->scaledtwidth;
-
-       if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
-               swidth       = 720;
-               totalwidth   = 858;
-               scaledtwidth = 858;
-       }
-
-       vdelay = tvnorm->vdelay;
-
-       xsf = (width*scaledtwidth)/swidth;
-       geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
-       geo->hdelay =  tvnorm->hdelayx1;
-       geo->hdelay =  (geo->hdelay*width)/swidth;
-       geo->hdelay &= 0x3fe;
-       sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
-       geo->vscale =  (0x10000UL-sr) & 0x1fff;
-       geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
-               ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
-       geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
-       geo->vdelay  =  vdelay;
-       geo->width   =  width;
-       geo->sheight =  tvnorm->sheight;
-       geo->vtotal  =  tvnorm->vtotal;
-
-       if (btv->opt_combfilter) {
-               geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
-               geo->comb = (width < 769) ? 1 : 0;
-       } else {
-               geo->vtc  = 0;
-               geo->comb = 0;
-       }
-}
-
-static void
-bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
-{
-       int off = odd ? 0x80 : 0x00;
-
-       if (geo->comb)
-               btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-       else
-               btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
-
-       btwrite(geo->vtc,             BT848_E_VTC+off);
-       btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
-       btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
-       btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
-       btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
-       btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
-       btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
-       btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
-       btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
-       btwrite(geo->crop,            BT848_E_CROP+off);
-       btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
-       btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
-}
-
-/* ---------------------------------------------------------- */
-/* risc group / risc main loop / dma management               */
-
-void
-bttv_set_dma(struct bttv *btv, int override)
-{
-       unsigned long cmd;
-       int capctl;
-
-       btv->cap_ctl = 0;
-       if (NULL != btv->curr.top)      btv->cap_ctl |= 0x02;
-       if (NULL != btv->curr.bottom)   btv->cap_ctl |= 0x01;
-       if (NULL != btv->cvbi)          btv->cap_ctl |= 0x0c;
-
-       capctl  = 0;
-       capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00;  /* capture  */
-       capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00;  /* vbi data */
-       capctl |= override;
-
-       d2printk(KERN_DEBUG
-                "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
-                btv->c.nr,capctl,btv->loop_irq,
-                btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
-                btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
-                btv->cvbi         ? (unsigned long long)btv->cvbi->bottom.dma         : 0,
-                btv->curr.bottom  ? (unsigned long long)btv->curr.bottom->bottom.dma  : 0);
-
-       cmd = BT848_RISC_JUMP;
-       if (btv->loop_irq) {
-               cmd |= BT848_RISC_IRQ;
-               cmd |= (btv->loop_irq  & 0x0f) << 16;
-               cmd |= (~btv->loop_irq & 0x0f) << 20;
-       }
-       if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
-               mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
-       } else {
-               del_timer(&btv->timeout);
-       }
-       btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
-
-       btaor(capctl, ~0x0f, BT848_CAP_CTL);
-       if (capctl) {
-               if (btv->dma_on)
-                       return;
-               btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
-               btor(3, BT848_GPIO_DMA_CTL);
-               btv->dma_on = 1;
-       } else {
-               if (!btv->dma_on)
-                       return;
-               btand(~3, BT848_GPIO_DMA_CTL);
-               btv->dma_on = 0;
-       }
-       return;
-}
-
-int
-bttv_risc_init_main(struct bttv *btv)
-{
-       int rc;
-
-       if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
-               return rc;
-       dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
-               btv->c.nr,(unsigned long long)btv->main.dma);
-
-       btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
-                                      BT848_FIFO_STATUS_VRE);
-       btv->main.cpu[1] = cpu_to_le32(0);
-       btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
-       btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
-
-       /* top field */
-       btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
-       btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
-       btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
-       btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
-
-       btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
-                                      BT848_FIFO_STATUS_VRO);
-       btv->main.cpu[9] = cpu_to_le32(0);
-
-       /* bottom field */
-       btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
-       btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
-       btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
-       btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
-
-       /* jump back to top field */
-       btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
-       btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
-
-       return 0;
-}
-
-int
-bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
-              int irqflags)
-{
-       unsigned long cmd;
-       unsigned long next = btv->main.dma + ((slot+2) << 2);
-
-       if (NULL == risc) {
-               d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
-                        btv->c.nr,risc,slot);
-               btv->main.cpu[slot+1] = cpu_to_le32(next);
-       } else {
-               d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
-                        btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
-               cmd = BT848_RISC_JUMP;
-               if (irqflags) {
-                       cmd |= BT848_RISC_IRQ;
-                       cmd |= (irqflags  & 0x0f) << 16;
-                       cmd |= (~irqflags & 0x0f) << 20;
-               }
-               risc->jmp[0] = cpu_to_le32(cmd);
-               risc->jmp[1] = cpu_to_le32(next);
-               btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
-       }
-       return 0;
-}
-
-void
-bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
-{
-       BUG_ON(in_interrupt());
-       videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma);
-       videobuf_dma_free(&buf->vb.dma);
-       btcx_riscmem_free(btv->c.pci,&buf->bottom);
-       btcx_riscmem_free(btv->c.pci,&buf->top);
-       buf->vb.state = STATE_NEEDS_INIT;
-}
-
-int
-bttv_buffer_activate_vbi(struct bttv *btv,
-                        struct bttv_buffer *vbi)
-{
-       /* vbi capture */
-       if (vbi) {
-               vbi->vb.state = STATE_ACTIVE;
-               list_del(&vbi->vb.queue);
-               bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top,    0);
-               bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
-       } else {
-               bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
-               bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
-       }
-       return 0;
-}
-
-int
-bttv_buffer_activate_video(struct bttv *btv,
-                          struct bttv_buffer_set *set)
-{
-       /* video capture */
-       if (NULL != set->top  &&  NULL != set->bottom) {
-               if (set->top == set->bottom) {
-                       set->top->vb.state    = STATE_ACTIVE;
-                       if (set->top->vb.queue.next)
-                               list_del(&set->top->vb.queue);
-               } else {
-                       set->top->vb.state    = STATE_ACTIVE;
-                       set->bottom->vb.state = STATE_ACTIVE;
-                       if (set->top->vb.queue.next)
-                               list_del(&set->top->vb.queue);
-                       if (set->bottom->vb.queue.next)
-                               list_del(&set->bottom->vb.queue);
-               }
-               bttv_apply_geo(btv, &set->top->geo, 1);
-               bttv_apply_geo(btv, &set->bottom->geo,0);
-               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
-                              set->top_irq);
-               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
-                              set->frame_irq);
-               btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
-                     ~0xff, BT848_COLOR_FMT);
-               btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
-                     ~0x0f, BT848_COLOR_CTL);
-       } else if (NULL != set->top) {
-               set->top->vb.state  = STATE_ACTIVE;
-               if (set->top->vb.queue.next)
-                       list_del(&set->top->vb.queue);
-               bttv_apply_geo(btv, &set->top->geo,1);
-               bttv_apply_geo(btv, &set->top->geo,0);
-               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
-                              set->frame_irq);
-               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL,           0);
-               btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
-               btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
-       } else if (NULL != set->bottom) {
-               set->bottom->vb.state = STATE_ACTIVE;
-               if (set->bottom->vb.queue.next)
-                       list_del(&set->bottom->vb.queue);
-               bttv_apply_geo(btv, &set->bottom->geo,1);
-               bttv_apply_geo(btv, &set->bottom->geo,0);
-               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
-               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
-                              set->frame_irq);
-               btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
-               btaor(set->bottom->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
-       } else {
-               bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
-               bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
-       }
-       return 0;
-}
-
-/* ---------------------------------------------------------- */
-
-/* calculate geometry, build risc code */
-int
-bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
-{
-       const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
-
-       dprintk(KERN_DEBUG
-               "bttv%d: buffer field: %s  format: %s  size: %dx%d\n",
-               btv->c.nr, v4l2_field_names[buf->vb.field],
-               buf->fmt->name, buf->vb.width, buf->vb.height);
-
-       /* packed pixel modes */
-       if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
-               int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
-               int bpf = bpl * (buf->vb.height >> 1);
-
-               bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
-                             V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
-
-               switch (buf->vb.field) {
-               case V4L2_FIELD_TOP:
-                       bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
-                                        0,bpl,0,buf->vb.height);
-                       break;
-               case V4L2_FIELD_BOTTOM:
-                       bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
-                                        0,bpl,0,buf->vb.height);
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
-                                        0,bpl,bpl,buf->vb.height >> 1);
-                       bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
-                                        bpl,bpl,bpl,buf->vb.height >> 1);
-                       break;
-               case V4L2_FIELD_SEQ_TB:
-                       bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
-                                        0,bpl,0,buf->vb.height >> 1);
-                       bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
-                                        bpf,bpl,0,buf->vb.height >> 1);
-                       break;
-               default:
-                       BUG();
-               }
-       }
-
-       /* planar modes */
-       if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
-               int uoffset, voffset;
-               int ypadding, cpadding, lines;
-
-               /* calculate chroma offsets */
-               uoffset = buf->vb.width * buf->vb.height;
-               voffset = buf->vb.width * buf->vb.height;
-               if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
-                       /* Y-Cr-Cb plane order */
-                       uoffset >>= buf->fmt->hshift;
-                       uoffset >>= buf->fmt->vshift;
-                       uoffset  += voffset;
-               } else {
-                       /* Y-Cb-Cr plane order */
-                       voffset >>= buf->fmt->hshift;
-                       voffset >>= buf->fmt->vshift;
-                       voffset  += uoffset;
-               }
-
-               switch (buf->vb.field) {
-               case V4L2_FIELD_TOP:
-                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,0,buf->tvnorm);
-                       bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
-                                        0,buf->vb.width,0,buf->vb.height,
-                                        uoffset,voffset,buf->fmt->hshift,
-                                        buf->fmt->vshift,0);
-                       break;
-               case V4L2_FIELD_BOTTOM:
-                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,0,buf->tvnorm);
-                       bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
-                                        0,buf->vb.width,0,buf->vb.height,
-                                        uoffset,voffset,buf->fmt->hshift,
-                                        buf->fmt->vshift,0);
-                       break;
-               case V4L2_FIELD_INTERLACED:
-                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,1,buf->tvnorm);
-                       lines    = buf->vb.height >> 1;
-                       ypadding = buf->vb.width;
-                       cpadding = buf->vb.width >> buf->fmt->hshift;
-                       bttv_risc_planar(btv,&buf->top,
-                                        buf->vb.dma.sglist,
-                                        0,buf->vb.width,ypadding,lines,
-                                        uoffset,voffset,
-                                        buf->fmt->hshift,
-                                        buf->fmt->vshift,
-                                        cpadding);
-                       bttv_risc_planar(btv,&buf->bottom,
-                                        buf->vb.dma.sglist,
-                                        ypadding,buf->vb.width,ypadding,lines,
-                                        uoffset+cpadding,
-                                        voffset+cpadding,
-                                        buf->fmt->hshift,
-                                        buf->fmt->vshift,
-                                        cpadding);
-                       break;
-               case V4L2_FIELD_SEQ_TB:
-                       bttv_calc_geo(btv,&buf->geo,buf->vb.width,
-                                     buf->vb.height,1,buf->tvnorm);
-                       lines    = buf->vb.height >> 1;
-                       ypadding = buf->vb.width;
-                       cpadding = buf->vb.width >> buf->fmt->hshift;
-                       bttv_risc_planar(btv,&buf->top,
-                                        buf->vb.dma.sglist,
-                                        0,buf->vb.width,0,lines,
-                                        uoffset >> 1,
-                                        voffset >> 1,
-                                        buf->fmt->hshift,
-                                        buf->fmt->vshift,
-                                        0);
-                       bttv_risc_planar(btv,&buf->bottom,
-                                        buf->vb.dma.sglist,
-                                        lines * ypadding,buf->vb.width,0,lines,
-                                        lines * ypadding + (uoffset >> 1),
-                                        lines * ypadding + (voffset >> 1),
-                                        buf->fmt->hshift,
-                                        buf->fmt->vshift,
-                                        0);
-                       break;
-               default:
-                       BUG();
-               }
-       }
-
-       /* raw data */
-       if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
-               /* build risc code */
-               buf->vb.field = V4L2_FIELD_SEQ_TB;
-               bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
-                             1,buf->tvnorm);
-               bttv_risc_packed(btv, &buf->top,  buf->vb.dma.sglist,
-                                0, RAW_BPL, 0, RAW_LINES);
-               bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
-                                buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
-       }
-
-       /* copy format info */
-       buf->btformat = buf->fmt->btformat;
-       buf->btswap   = buf->fmt->btswap;
-       return 0;
-}
-
-/* ---------------------------------------------------------- */
-
-/* calculate geometry, build risc code */
-int
-bttv_overlay_risc(struct bttv *btv,
-                 struct bttv_overlay *ov,
-                 const struct bttv_format *fmt,
-                 struct bttv_buffer *buf)
-{
-       /* check interleave, bottom+top fields */
-       dprintk(KERN_DEBUG
-               "bttv%d: overlay fields: %s format: %s  size: %dx%d\n",
-               btv->c.nr, v4l2_field_names[buf->vb.field],
-               fmt->name,ov->w.width,ov->w.height);
-
-       /* calculate geometry */
-       bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
-                     V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
-
-       /* build risc code */
-       switch (ov->field) {
-       case V4L2_FIELD_TOP:
-               bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 0);
-               break;
-       case V4L2_FIELD_BOTTOM:
-               bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
-               break;
-       case V4L2_FIELD_INTERLACED:
-               bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 1);
-               bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
-               break;
-       default:
-               BUG();
-       }
-
-       /* copy format info */
-       buf->btformat = fmt->btformat;
-       buf->btswap   = fmt->btswap;
-       buf->vb.field = ov->field;
-       return 0;
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c
deleted file mode 100644 (file)
index 72afdd6..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
-
-    bttv - Bt848 frame grabber driver
-    vbi interface
-
-    (c) 2002 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kdev_t.h>
-#include <asm/io.h>
-#include "bttvp.h"
-
-/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
-   bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
-   HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
-   of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
-#define VBI_OFFSET ((64 + 0) * 2)
-
-#define VBI_DEFLINES 16
-#define VBI_MAXLINES 32
-
-static unsigned int vbibufs = 4;
-static unsigned int vbi_debug = 0;
-
-module_param(vbibufs,   int, 0444);
-module_param(vbi_debug, int, 0644);
-MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4");
-MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
-
-#ifdef dprintk
-# undef dprintk
-#endif
-#define dprintk(fmt, arg...)   if (vbi_debug) \
-       printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
-
-/* ----------------------------------------------------------------------- */
-/* vbi risc code + mm                                                      */
-
-static int
-vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
-{
-       int bpl = 2048;
-
-       bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
-                        0, bpl-4, 4, lines);
-       bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
-                        lines * bpl, bpl-4, 4, lines);
-       return 0;
-}
-
-static int vbi_buffer_setup(struct videobuf_queue *q,
-                           unsigned int *count, unsigned int *size)
-{
-       struct bttv_fh *fh = q->priv_data;
-       struct bttv *btv = fh->btv;
-
-       if (0 == *count)
-               *count = vbibufs;
-       *size = fh->lines * 2 * 2048;
-       dprintk("setup: lines=%d\n",fh->lines);
-       return 0;
-}
-
-static int vbi_buffer_prepare(struct videobuf_queue *q,
-                             struct videobuf_buffer *vb,
-                             enum v4l2_field field)
-{
-       struct bttv_fh *fh = q->priv_data;
-       struct bttv *btv = fh->btv;
-       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
-       int rc;
-
-       buf->vb.size = fh->lines * 2 * 2048;
-       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-               return -EINVAL;
-
-       if (STATE_NEEDS_INIT == buf->vb.state) {
-               if (0 != (rc = videobuf_iolock(btv->c.pci, &buf->vb, NULL)))
-                       goto fail;
-               if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
-                       goto fail;
-       }
-       buf->vb.state = STATE_PREPARED;
-       buf->vb.field = field;
-       dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
-               vb, &buf->top, &buf->bottom,
-               v4l2_field_names[buf->vb.field]);
-       return 0;
-
- fail:
-       bttv_dma_free(btv,buf);
-       return rc;
-}
-
-static void
-vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-       struct bttv_fh *fh = q->priv_data;
-       struct bttv *btv = fh->btv;
-       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
-
-       dprintk("queue %p\n",vb);
-       buf->vb.state = STATE_QUEUED;
-       list_add_tail(&buf->vb.queue,&btv->vcapture);
-       if (NULL == btv->cvbi) {
-               fh->btv->loop_irq |= 4;
-               bttv_set_dma(btv,0x0c);
-       }
-}
-
-static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
-       struct bttv_fh *fh = q->priv_data;
-       struct bttv *btv = fh->btv;
-       struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
-
-       dprintk("free %p\n",vb);
-       bttv_dma_free(fh->btv,buf);
-}
-
-struct videobuf_queue_ops bttv_vbi_qops = {
-       .buf_setup    = vbi_buffer_setup,
-       .buf_prepare  = vbi_buffer_prepare,
-       .buf_queue    = vbi_buffer_queue,
-       .buf_release  = vbi_buffer_release,
-};
-
-/* ----------------------------------------------------------------------- */
-
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
-{
-       int vdelay;
-
-       if (lines < 1)
-               lines = 1;
-       if (lines > VBI_MAXLINES)
-               lines = VBI_MAXLINES;
-       fh->lines = lines;
-
-       vdelay = btread(BT848_E_VDELAY_LO);
-       if (vdelay < lines*2) {
-               vdelay = lines*2;
-               btwrite(vdelay,BT848_E_VDELAY_LO);
-               btwrite(vdelay,BT848_O_VDELAY_LO);
-       }
-}
-
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
-{
-       const struct bttv_tvnorm *tvnorm;
-       s64 count0,count1,count;
-
-       tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
-       f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
-       f->fmt.vbi.samples_per_line = 2048;
-       f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = VBI_OFFSET;
-       f->fmt.vbi.flags            = 0;
-
-       /* s64 to prevent overflow. */
-       count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
-               - tvnorm->vbistart[0];
-       count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
-               - tvnorm->vbistart[1];
-       count  = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES);
-
-       f->fmt.vbi.start[0] = tvnorm->vbistart[0];
-       f->fmt.vbi.start[1] = tvnorm->vbistart[1];
-       f->fmt.vbi.count[0] = count;
-       f->fmt.vbi.count[1] = count;
-
-       f->fmt.vbi.reserved[0] = 0;
-       f->fmt.vbi.reserved[1] = 0;
-}
-
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
-{
-       const struct bttv_tvnorm *tvnorm;
-
-       tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
-       memset(f,0,sizeof(*f));
-       f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       f->fmt.vbi.sampling_rate    = tvnorm->Fsc;
-       f->fmt.vbi.samples_per_line = 2048;
-       f->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
-       f->fmt.vbi.offset           = VBI_OFFSET;
-       f->fmt.vbi.start[0]         = tvnorm->vbistart[0];
-       f->fmt.vbi.start[1]         = tvnorm->vbistart[1];
-       f->fmt.vbi.count[0]         = fh->lines;
-       f->fmt.vbi.count[1]         = fh->lines;
-       f->fmt.vbi.flags            = 0;
-}
-
-/* ----------------------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
deleted file mode 100644 (file)
index 9908c8e..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- *
- *  bttv - Bt848 frame grabber driver
- *
- *  card ID's and external interfaces of the bttv driver
- *  basically stuff needed by other drivers (i2c, lirc, ...)
- *  and is supported not to change much over time.
- *
- *  Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
- *  (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
-
-#ifndef _BTTV_H_
-#define _BTTV_H_
-
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <media/ir-common.h>
-#include <media/ir-kbd-i2c.h>
-
-/* ---------------------------------------------------------- */
-/* exported by bttv-cards.c                                   */
-
-#define BTTV_BOARD_UNKNOWN                 0x00
-#define BTTV_BOARD_MIRO                    0x01
-#define BTTV_BOARD_HAUPPAUGE               0x02
-#define BTTV_BOARD_STB                     0x03
-#define BTTV_BOARD_INTEL                   0x04
-#define BTTV_BOARD_DIAMOND                 0x05
-#define BTTV_BOARD_AVERMEDIA               0x06
-#define BTTV_BOARD_MATRIX_VISION           0x07
-#define BTTV_BOARD_FLYVIDEO                0x08
-#define BTTV_BOARD_TURBOTV                 0x09
-#define BTTV_BOARD_HAUPPAUGE878            0x0a
-#define BTTV_BOARD_MIROPRO                 0x0b
-#define BTTV_BOARD_ADSTECH_TV              0x0c
-#define BTTV_BOARD_AVERMEDIA98             0x0d
-#define BTTV_BOARD_VHX                     0x0e
-#define BTTV_BOARD_ZOLTRIX                 0x0f
-#define BTTV_BOARD_PIXVIEWPLAYTV           0x10
-#define BTTV_BOARD_WINVIEW_601             0x11
-#define BTTV_BOARD_AVEC_INTERCAP           0x12
-#define BTTV_BOARD_LIFE_FLYKIT             0x13
-#define BTTV_BOARD_CEI_RAFFLES             0x14
-#define BTTV_BOARD_CONFERENCETV            0x15
-#define BTTV_BOARD_PHOEBE_TVMAS            0x16
-#define BTTV_BOARD_MODTEC_205              0x17
-#define BTTV_BOARD_MAGICTVIEW061           0x18
-#define BTTV_BOARD_VOBIS_BOOSTAR           0x19
-#define BTTV_BOARD_HAUPPAUG_WCAM           0x1a
-#define BTTV_BOARD_MAXI                    0x1b
-#define BTTV_BOARD_TERRATV                 0x1c
-#define BTTV_BOARD_PXC200                  0x1d
-#define BTTV_BOARD_FLYVIDEO_98             0x1e
-#define BTTV_BOARD_IPROTV                  0x1f
-#define BTTV_BOARD_INTEL_C_S_PCI           0x20
-#define BTTV_BOARD_TERRATVALUE             0x21
-#define BTTV_BOARD_WINFAST2000             0x22
-#define BTTV_BOARD_CHRONOS_VS2             0x23
-#define BTTV_BOARD_TYPHOON_TVIEW           0x24
-#define BTTV_BOARD_PXELVWPLTVPRO           0x25
-#define BTTV_BOARD_MAGICTVIEW063           0x26
-#define BTTV_BOARD_PINNACLE                0x27
-#define BTTV_BOARD_STB2                    0x28
-#define BTTV_BOARD_AVPHONE98               0x29
-#define BTTV_BOARD_PV951                   0x2a
-#define BTTV_BOARD_ONAIR_TV                0x2b
-#define BTTV_BOARD_SIGMA_TVII_FM           0x2c
-#define BTTV_BOARD_MATRIX_VISION2          0x2d
-#define BTTV_BOARD_ZOLTRIX_GENIE           0x2e
-#define BTTV_BOARD_TERRATVRADIO            0x2f
-#define BTTV_BOARD_DYNALINK                0x30
-#define BTTV_BOARD_GVBCTV3PCI              0x31
-#define BTTV_BOARD_PXELVWPLTVPAK           0x32
-#define BTTV_BOARD_EAGLE                   0x33
-#define BTTV_BOARD_PINNACLEPRO             0x34
-#define BTTV_BOARD_TVIEW_RDS_FM            0x35
-#define BTTV_BOARD_LIFETEC_9415            0x36
-#define BTTV_BOARD_BESTBUY_EASYTV          0x37
-#define BTTV_BOARD_FLYVIDEO_98FM           0x38
-#define BTTV_BOARD_GRANDTEC                0x39
-#define BTTV_BOARD_ASKEY_CPH060            0x3a
-#define BTTV_BOARD_ASKEY_CPH03X            0x3b
-#define BTTV_BOARD_MM100PCTV               0x3c
-#define BTTV_BOARD_GMV1                    0x3d
-#define BTTV_BOARD_BESTBUY_EASYTV2         0x3e
-#define BTTV_BOARD_ATI_TVWONDER            0x3f
-#define BTTV_BOARD_ATI_TVWONDERVE          0x40
-#define BTTV_BOARD_FLYVIDEO2000            0x41
-#define BTTV_BOARD_TERRATVALUER            0x42
-#define BTTV_BOARD_GVBCTV4PCI              0x43
-#define BTTV_BOARD_VOODOOTV_FM             0x44
-#define BTTV_BOARD_AIMMS                   0x45
-#define BTTV_BOARD_PV_BT878P_PLUS          0x46
-#define BTTV_BOARD_FLYVIDEO98EZ            0x47
-#define BTTV_BOARD_PV_BT878P_9B            0x48
-#define BTTV_BOARD_SENSORAY311             0x49
-#define BTTV_BOARD_RV605                   0x4a
-#define BTTV_BOARD_POWERCLR_MTV878         0x4b
-#define BTTV_BOARD_WINDVR                  0x4c
-#define BTTV_BOARD_GRANDTEC_MULTI          0x4d
-#define BTTV_BOARD_KWORLD                  0x4e
-#define BTTV_BOARD_DSP_TCVIDEO             0x4f
-#define BTTV_BOARD_HAUPPAUGEPVR            0x50
-#define BTTV_BOARD_GVBCTV5PCI              0x51
-#define BTTV_BOARD_OSPREY1x0               0x52
-#define BTTV_BOARD_OSPREY1x0_848           0x53
-#define BTTV_BOARD_OSPREY101_848           0x54
-#define BTTV_BOARD_OSPREY1x1               0x55
-#define BTTV_BOARD_OSPREY1x1_SVID          0x56
-#define BTTV_BOARD_OSPREY2xx               0x57
-#define BTTV_BOARD_OSPREY2x0_SVID          0x58
-#define BTTV_BOARD_OSPREY2x0               0x59
-#define BTTV_BOARD_OSPREY500               0x5a
-#define BTTV_BOARD_OSPREY540               0x5b
-#define BTTV_BOARD_OSPREY2000              0x5c
-#define BTTV_BOARD_IDS_EAGLE               0x5d
-#define BTTV_BOARD_PINNACLESAT             0x5e
-#define BTTV_BOARD_FORMAC_PROTV            0x5f
-#define BTTV_BOARD_MACHTV                  0x60
-#define BTTV_BOARD_EURESYS_PICOLO          0x61
-#define BTTV_BOARD_PV150                   0x62
-#define BTTV_BOARD_AD_TVK503               0x63
-#define BTTV_BOARD_HERCULES_SM_TV          0x64
-#define BTTV_BOARD_PACETV                  0x65
-#define BTTV_BOARD_IVC200                  0x66
-#define BTTV_BOARD_XGUARD                  0x67
-#define BTTV_BOARD_NEBULA_DIGITV           0x68
-#define BTTV_BOARD_PV143                   0x69
-#define BTTV_BOARD_VD009X1_MINIDIN         0x6a
-#define BTTV_BOARD_VD009X1_COMBI           0x6b
-#define BTTV_BOARD_VD009_MINIDIN           0x6c
-#define BTTV_BOARD_VD009_COMBI             0x6d
-#define BTTV_BOARD_IVC100                  0x6e
-#define BTTV_BOARD_IVC120                  0x6f
-#define BTTV_BOARD_PC_HDTV                 0x70
-#define BTTV_BOARD_TWINHAN_DST             0x71
-#define BTTV_BOARD_WINFASTVC100            0x72
-#define BTTV_BOARD_TEV560                  0x73
-#define BTTV_BOARD_SIMUS_GVC1100           0x74
-#define BTTV_BOARD_NGSTV_PLUS              0x75
-#define BTTV_BOARD_LMLBT4                  0x76
-#define BTTV_BOARD_TEKRAM_M205             0x77
-#define BTTV_BOARD_CONTVFMI                0x78
-#define BTTV_BOARD_PICOLO_TETRA_CHIP       0x79
-#define BTTV_BOARD_SPIRIT_TV               0x7a
-#define BTTV_BOARD_AVDVBT_771              0x7b
-#define BTTV_BOARD_AVDVBT_761              0x7c
-#define BTTV_BOARD_MATRIX_VISIONSQ         0x7d
-#define BTTV_BOARD_MATRIX_VISIONSLC        0x7e
-#define BTTV_BOARD_APAC_VIEWCOMP           0x7f
-#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
-#define BTTV_BOARD_VGEAR_MYVCD             0x81
-#define BTTV_BOARD_SUPER_TV                0x82
-#define BTTV_BOARD_TIBET_CS16              0x83
-#define BTTV_BOARD_KODICOM_4400R           0x84
-#define BTTV_BOARD_KODICOM_4400R_SL        0x85
-#define BTTV_BOARD_ADLINK_RTV24            0x86
-#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
-#define BTTV_BOARD_ACORP_Y878F             0x88
-#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2    0x89
-#define BTTV_BOARD_PV_BT878P_2E            0x8a
-#define BTTV_BOARD_PV_M4900                0x8b
-#define BTTV_BOARD_OSPREY440               0x8c
-#define BTTV_BOARD_ASOUND_SKYEYE          0x8d
-#define BTTV_BOARD_SABRENT_TVFM           0x8e
-#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB     0x8f
-#define BTTV_BOARD_MACHTV_MAGICTV          0x90
-
-/* i2c address list */
-#define I2C_TSA5522        0xc2
-#define I2C_TDA7432        0x8a
-#define I2C_BT832_ALT1    0x88
-#define I2C_BT832_ALT2    0x8a // alternate setting
-#define I2C_TDA8425        0x82
-#define I2C_TDA9840        0x84
-#define I2C_TDA9850        0xb6 /* also used by 9855,9873 */
-#define I2C_TDA9874        0xb0 /* also used by 9875 */
-#define I2C_TDA9875        0xb0
-#define I2C_HAUPEE         0xa0
-#define I2C_STBEE          0xae
-#define I2C_VHX            0xc0
-#define I2C_MSP3400        0x80
-#define I2C_MSP3400_ALT    0x88
-#define I2C_TEA6300        0x80 /* also used by 6320 */
-#define I2C_DPL3518       0x84
-#define I2C_TDA9887       0x86
-
-/* more card-specific defines */
-#define PT2254_L_CHANNEL 0x10
-#define PT2254_R_CHANNEL 0x08
-#define PT2254_DBS_IN_2 0x400
-#define PT2254_DBS_IN_10 0x20000
-#define WINVIEW_PT2254_CLK  0x40
-#define WINVIEW_PT2254_DATA 0x20
-#define WINVIEW_PT2254_STROBE 0x80
-
-/* digital_mode */
-#define DIGITAL_MODE_VIDEO 1
-#define DIGITAL_MODE_CAMERA 2
-
-struct bttv_core {
-       /* device structs */
-       struct pci_dev       *pci;
-       struct i2c_adapter   i2c_adap;
-       struct list_head     subs;     /* struct bttv_sub_device */
-
-       /* device config */
-       unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
-       unsigned int         type;     /* card type (pointer into tvcards[])  */
-       char                 name[8];  /* dev name */
-};
-
-struct bttv;
-
-
-struct bttv_ir {
-       struct input_dev        *dev;
-       struct ir_input_state   ir;
-       char                    name[32];
-       char                    phys[32];
-
-       /* Usual gpio signalling */
-
-       u32                     mask_keycode;
-       u32                     mask_keydown;
-       u32                     mask_keyup;
-       u32                     polling;
-       u32                     last_gpio;
-       struct work_struct      work;
-       struct timer_list       timer;
-
-       /* RC5 gpio */
-       u32 rc5_gpio;
-       struct timer_list timer_end;    /* timer_end for code completion */
-       struct timer_list timer_keyup;  /* timer_end for key release */
-       u32 last_rc5;                   /* last good rc5 code */
-       u32 last_bit;                   /* last raw bit seen */
-       u32 code;                       /* raw code under construction */
-       struct timeval base_time;       /* time of last seen code */
-       int active;                     /* building raw code */
-};
-
-struct tvcard
-{
-       char *name;
-       unsigned int video_inputs;
-       unsigned int audio_inputs;
-       unsigned int tuner;
-       unsigned int svhs;
-       unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
-       u32 gpiomask;
-       u32 muxsel[16];
-       u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
-       u32 gpiomask2;   /* GPIO MUX mask */
-
-       /* i2c audio flags */
-       unsigned int no_msp34xx:1;
-       unsigned int no_tda9875:1;
-       unsigned int no_tda7432:1;
-       unsigned int needs_tvaudio:1;
-       unsigned int msp34xx_alt:1;
-
-       /* flag: video pci function is unused */
-       unsigned int no_video:1;
-       unsigned int has_dvb:1;
-       unsigned int has_remote:1;
-       unsigned int no_gpioirq:1;
-
-       /* other settings */
-       unsigned int pll;
-#define PLL_NONE 0
-#define PLL_28   1
-#define PLL_35   2
-
-       unsigned int tuner_type;
-       unsigned int tuner_addr;
-       unsigned int radio_addr;
-
-       unsigned int has_radio;
-       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
-       void (*muxsel_hook)(struct bttv *btv, unsigned int input);
-};
-
-extern struct tvcard bttv_tvcards[];
-
-/* identification / initialization of the card */
-extern void bttv_idcard(struct bttv *btv);
-extern void bttv_init_card1(struct bttv *btv);
-extern void bttv_init_card2(struct bttv *btv);
-
-/* card-specific funtions */
-extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
-extern void bttv_tda9880_setnorm(struct bttv *btv, int norm);
-
-/* extra tweaks for some chipsets */
-extern void bttv_check_chipset(void);
-extern int bttv_handle_chipset(struct bttv *btv);
-
-/* ---------------------------------------------------------- */
-/* exported by bttv-if.c                                      */
-
-/* this obsolete -- please use the sysfs-based
-   interface below for new code */
-
-/* returns card type + card ID (for bt878-based ones)
-   for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
-   returns negative value if error occurred
-*/
-extern int bttv_get_cardinfo(unsigned int card, int *type,
-                            unsigned int *cardid);
-extern struct pci_dev* bttv_get_pcidev(unsigned int card);
-
-/* obsolete, use bttv_get_cardinfo instead */
-extern int bttv_get_id(unsigned int card);
-
-/* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
-   data | (current_GPOE_value & ~mask)
-   returns negative value if error occurred
-*/
-extern int bttv_gpio_enable(unsigned int card,
-                           unsigned long mask, unsigned long data);
-
-/* fills data with GPDATA register contents
-   returns negative value if error occurred
-*/
-extern int bttv_read_gpio(unsigned int card, unsigned long *data);
-
-/* sets GPDATA register to new value:
-  (data & mask) | (current_GPDATA_value & ~mask)
-  returns negative value if error occurred
-*/
-extern int bttv_write_gpio(unsigned int card,
-                          unsigned long mask, unsigned long data);
-
-/* returns pointer to task queue which can be used as parameter to
-   interruptible_sleep_on
-   in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
-   (wake_up_interruptible) and following call to the function bttv_read_gpio
-   should return new value of GPDATA,
-   returns NULL value if error occurred or queue is not available
-   WARNING: because there is no buffer for GPIO data, one MUST
-   process data ASAP
-*/
-extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
-
-/* call i2c clients
-*/
-extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
-
-
-
-/* ---------------------------------------------------------- */
-/* sysfs/driver-moded based gpio access interface             */
-
-
-struct bttv_sub_device {
-       struct device    dev;
-       struct bttv_core *core;
-       struct list_head list;
-};
-#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev)
-
-struct bttv_sub_driver {
-       struct device_driver   drv;
-       char                   wanted[BUS_ID_SIZE];
-       int                    (*probe)(struct bttv_sub_device *sub);
-       void                   (*remove)(struct bttv_sub_device *sub);
-       void                   (*gpio_irq)(struct bttv_sub_device *sub);
-};
-#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
-
-int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted);
-int bttv_sub_unregister(struct bttv_sub_driver *drv);
-
-/* gpio access functions */
-void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits);
-u32 bttv_gpio_read(struct bttv_core *core);
-void bttv_gpio_write(struct bttv_core *core, u32 value);
-void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
-
-#define gpio_inout(mask,bits)  bttv_gpio_inout(&btv->c, mask, bits)
-#define gpio_read()            bttv_gpio_read(&btv->c)
-#define gpio_write(value)      bttv_gpio_write(&btv->c, value)
-#define gpio_bits(mask,bits)   bttv_gpio_bits(&btv->c, mask, bits)
-
-
-/* ---------------------------------------------------------- */
-/* i2c                                                        */
-
-extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
-extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
-extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
-                        unsigned char b2, int both);
-extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
-
-extern int bttv_input_init(struct bttv *dev);
-extern void bttv_input_fini(struct bttv *dev);
-extern void bttv_input_irq(struct bttv *dev);
-
-#endif /* _BTTV_H_ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
deleted file mode 100644 (file)
index 9cb72f1..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
-
-    bttv - Bt848 frame grabber driver
-
-    bttv's *private* header file  --  nobody other than bttv itself
-    should ever include this file.
-
-    (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _BTTVP_H_
-#define _BTTVP_H_
-
-#include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
-
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
-#include <linux/pci.h>
-#include <linux/input.h>
-#include <linux/mutex.h>
-#include <asm/scatterlist.h>
-#include <asm/io.h>
-
-#include <linux/device.h>
-#include <media/video-buf.h>
-#include <media/audiochip.h>
-#include <media/tuner.h>
-#include <media/tveeprom.h>
-#include <media/ir-common.h>
-
-
-#include "bt848.h"
-#include "bttv.h"
-#include "btcx-risc.h"
-
-#ifdef __KERNEL__
-
-#define FORMAT_FLAGS_DITHER       0x01
-#define FORMAT_FLAGS_PACKED       0x02
-#define FORMAT_FLAGS_PLANAR       0x04
-#define FORMAT_FLAGS_RAW          0x08
-#define FORMAT_FLAGS_CrCb         0x10
-
-#define RISC_SLOT_O_VBI        4
-#define RISC_SLOT_O_FIELD      6
-#define RISC_SLOT_E_VBI       10
-#define RISC_SLOT_E_FIELD     12
-#define RISC_SLOT_LOOP        14
-
-#define RESOURCE_OVERLAY       1
-#define RESOURCE_VIDEO         2
-#define RESOURCE_VBI           4
-
-#define RAW_LINES            640
-#define RAW_BPL             1024
-
-#define UNSET (-1U)
-
-#define clamp(x, low, high) min (max (low, x), high)
-
-/* ---------------------------------------------------------- */
-
-struct bttv_tvnorm {
-       int   v4l2_id;
-       char  *name;
-       u32   Fsc;
-       u16   swidth, sheight; /* scaled standard width, height */
-       u16   totalwidth;
-       u8    adelay, bdelay, iform;
-       u32   scaledtwidth;
-       u16   hdelayx1, hactivex1;
-       u16   vdelay;
-       u8    vbipack;
-       u16   vtotal;
-       int   sram;
-       /* ITU-R frame line number of the first VBI line we can
-          capture, of the first and second field. */
-       u16   vbistart[2];
-};
-extern const struct bttv_tvnorm bttv_tvnorms[];
-
-struct bttv_format {
-       char *name;
-       int  palette;         /* video4linux 1      */
-       int  fourcc;          /* video4linux 2      */
-       int  btformat;        /* BT848_COLOR_FMT_*  */
-       int  btswap;          /* BT848_COLOR_CTL_*  */
-       int  depth;           /* bit/pixel          */
-       int  flags;
-       int  hshift,vshift;   /* for planar modes   */
-};
-
-/* ---------------------------------------------------------- */
-
-struct bttv_geometry {
-       u8  vtc,crop,comb;
-       u16 width,hscale,hdelay;
-       u16 sheight,vscale,vdelay,vtotal;
-};
-
-struct bttv_buffer {
-       /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer     vb;
-
-       /* bttv specific */
-       const struct bttv_format   *fmt;
-       int                        tvnorm;
-       int                        btformat;
-       int                        btswap;
-       struct bttv_geometry       geo;
-       struct btcx_riscmem        top;
-       struct btcx_riscmem        bottom;
-};
-
-struct bttv_buffer_set {
-       struct bttv_buffer     *top;       /* top field buffer    */
-       struct bttv_buffer     *bottom;    /* bottom field buffer */
-       unsigned int           top_irq;
-       unsigned int           frame_irq;
-};
-
-struct bttv_overlay {
-       int                    tvnorm;
-       struct v4l2_rect       w;
-       enum v4l2_field        field;
-       struct v4l2_clip       *clips;
-       int                    nclips;
-       int                    setup_ok;
-};
-
-struct bttv_fh {
-       struct bttv              *btv;
-       int resources;
-#ifdef VIDIOC_G_PRIORITY
-       enum v4l2_priority       prio;
-#endif
-       enum v4l2_buf_type       type;
-
-       /* video capture */
-       struct videobuf_queue    cap;
-       const struct bttv_format *fmt;
-       int                      width;
-       int                      height;
-
-       /* current settings */
-       const struct bttv_format *ovfmt;
-       struct bttv_overlay      ov;
-
-       /* video overlay */
-       struct videobuf_queue    vbi;
-       int                      lines;
-};
-
-/* ---------------------------------------------------------- */
-/* bttv-risc.c                                                */
-
-/* risc code generators - capture */
-int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
-                    struct scatterlist *sglist,
-                    unsigned int offset, unsigned int bpl,
-                    unsigned int pitch, unsigned int lines);
-
-/* control dma register + risc main loop */
-void bttv_set_dma(struct bttv *btv, int override);
-int bttv_risc_init_main(struct bttv *btv);
-int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
-                  int irqflags);
-
-/* capture buffer handling */
-int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf);
-int bttv_buffer_activate_video(struct bttv *btv,
-                              struct bttv_buffer_set *set);
-int bttv_buffer_activate_vbi(struct bttv *btv,
-                            struct bttv_buffer *vbi);
-void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf);
-
-/* overlay handling */
-int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
-                     const struct bttv_format *fmt,
-                     struct bttv_buffer *buf);
-
-
-/* ---------------------------------------------------------- */
-/* bttv-vbi.c                                                 */
-
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
-
-extern struct videobuf_queue_ops bttv_vbi_qops;
-
-/* ---------------------------------------------------------- */
-/* bttv-gpio.c */
-
-
-extern struct bus_type bttv_sub_bus_type;
-int bttv_sub_add_device(struct bttv_core *core, char *name);
-int bttv_sub_del_devices(struct bttv_core *core);
-void bttv_gpio_irq(struct bttv_core *core);
-
-
-/* ---------------------------------------------------------- */
-/* bttv-driver.c                                              */
-
-/* insmod options */
-extern unsigned int bttv_verbose;
-extern unsigned int bttv_debug;
-extern unsigned int bttv_gpio;
-extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
-extern int init_bttv_i2c(struct bttv *btv);
-extern int fini_bttv_i2c(struct bttv *btv);
-
-#define bttv_printk if (bttv_verbose) printk
-#define dprintk  if (bttv_debug >= 1) printk
-#define d2printk if (bttv_debug >= 2) printk
-
-#define BTTV_MAX_FBUF   0x208000
-#define VBIBUF_SIZE     (2048*VBI_MAXLINES*2)
-#define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE  (HZ)   /* one second */
-
-
-struct bttv_pll_info {
-       unsigned int pll_ifreq;    /* PLL input frequency        */
-       unsigned int pll_ofreq;    /* PLL output frequency       */
-       unsigned int pll_crystal;  /* Crystal used for input     */
-       unsigned int pll_current;  /* Currently programmed ofreq */
-};
-
-/* for gpio-connected remote control */
-struct bttv_input {
-       struct input_dev      *dev;
-       struct ir_input_state ir;
-       char                  name[32];
-       char                  phys[32];
-       u32                   mask_keycode;
-       u32                   mask_keydown;
-};
-
-struct bttv_suspend_state {
-       u32  gpio_enable;
-       u32  gpio_data;
-       int  disabled;
-       int  loop_irq;
-       struct bttv_buffer_set video;
-       struct bttv_buffer     *vbi;
-};
-
-struct bttv {
-       struct bttv_core c;
-
-       /* pci device config */
-       unsigned short id;
-       unsigned char revision;
-       unsigned char __iomem *bt848_mmio;   /* pointer to mmio */
-
-       /* card configuration info */
-       unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
-       unsigned int tuner_type;  /* tuner chip type */
-       unsigned int tda9887_conf;
-       unsigned int svhs;
-       struct bttv_pll_info pll;
-       int triton1;
-       int gpioirq;
-       int (*custom_irq)(struct bttv *btv);
-
-       int use_i2c_hw;
-
-       /* old gpio interface */
-       wait_queue_head_t gpioq;
-       int shutdown;
-       void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
-
-       /* new gpio interface */
-       spinlock_t gpio_lock;
-
-       /* i2c layer */
-       struct i2c_algo_bit_data   i2c_algo;
-       struct i2c_client          i2c_client;
-       int                        i2c_state, i2c_rc;
-       int                        i2c_done;
-       wait_queue_head_t          i2c_queue;
-
-       /* video4linux (1) */
-       struct video_device *video_dev;
-       struct video_device *radio_dev;
-       struct video_device *vbi_dev;
-
-       /* infrared remote */
-       int has_remote;
-       struct bttv_ir *remote;
-
-       /* locking */
-       spinlock_t s_lock;
-       struct mutex lock;
-       int resources;
-       struct mutex reslock;
-#ifdef VIDIOC_G_PRIORITY
-       struct v4l2_prio_state prio;
-#endif
-
-       /* video state */
-       unsigned int input;
-       unsigned int audio;
-       unsigned long freq;
-       int tvnorm,hue,contrast,bright,saturation;
-       struct v4l2_framebuffer fbuf;
-       unsigned int field_count;
-
-       /* various options */
-       int opt_combfilter;
-       int opt_lumafilter;
-       int opt_automute;
-       int opt_chroma_agc;
-       int opt_adc_crush;
-       int opt_vcr_hack;
-       int opt_whitecrush_upper;
-       int opt_whitecrush_lower;
-       int opt_uv_ratio;
-       int opt_full_luma_range;
-       int opt_coring;
-
-       /* radio data/state */
-       int has_radio;
-       int radio_user;
-
-       /* miro/pinnacle + Aimslab VHX
-          philips matchbox (tea5757 radio tuner) support */
-       int has_matchbox;
-       int mbox_we;
-       int mbox_data;
-       int mbox_clk;
-       int mbox_most;
-       int mbox_mask;
-
-       /* ISA stuff (Terratec Active Radio Upgrade) */
-       int mbox_ior;
-       int mbox_iow;
-       int mbox_csel;
-
-       /* risc memory management data
-          - must aquire s_lock before changing these
-          - only the irq handler is supported to touch top + bottom + vcurr */
-       struct btcx_riscmem     main;
-       struct bttv_buffer      *screen;    /* overlay             */
-       struct list_head        capture;    /* video capture queue */
-       struct list_head        vcapture;   /* vbi capture queue   */
-       struct bttv_buffer_set  curr;       /* active buffers      */
-       struct bttv_buffer      *cvbi;      /* active vbi buffer   */
-       int                     loop_irq;
-       int                     new_input;
-
-       unsigned long cap_ctl;
-       unsigned long dma_on;
-       struct timer_list timeout;
-       struct bttv_suspend_state state;
-
-       /* stats */
-       unsigned int errors;
-       unsigned int framedrop;
-       unsigned int irq_total;
-       unsigned int irq_me;
-
-       unsigned int users;
-       struct bttv_fh init;
-};
-
-/* our devices */
-#define BTTV_MAX 16
-extern unsigned int bttv_num;
-extern struct bttv bttvs[BTTV_MAX];
-
-/* private ioctls */
-#define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
-#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
-
-#endif
-
-#define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
-#define btread(adr)         readl(btv->bt848_mmio+(adr))
-
-#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-#endif /* _BTTVP_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index d97b7d8ac33d687f9f7d0a46f32f069096d0e5c0..cf61c590f4ada90bb038e9e2b9610a4870336013 100644 (file)
@@ -150,7 +150,7 @@ static int qc_calibrate(struct qcam_device *q)
 static struct qcam_device *qcam_init(struct parport *port)
 {
        struct qcam_device *q;
-       
+
        q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
        if(q==NULL)
                return NULL;
@@ -158,16 +158,16 @@ static struct qcam_device *qcam_init(struct parport *port)
        q->pport = port;
        q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
                                          NULL, 0, NULL);
-       if (q->pdev == NULL) 
+       if (q->pdev == NULL)
        {
                printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
                       port->name);
                kfree(q);
                return NULL;
        }
-       
+
        memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-       
+
        mutex_init(&q->lock);
 
        q->port_mode = (QC_ANY | QC_NOTSET);
@@ -236,12 +236,12 @@ static int qc_waithand(struct qcam_device *q, int val)
                while (!((status = read_lpstatus(q)) & 8))
                {
                        /* 1000 is enough spins on the I/O for all normal
-                          cases, at that point we start to poll slowly 
+                          cases, at that point we start to poll slowly
                           until the camera wakes up. However, we are
                           busy blocked until the camera responds, so
                           setting it lower is much better for interactive
                           response. */
-                          
+
                        if(runs++>maxpoll)
                        {
                                msleep_interruptible(5);
@@ -255,12 +255,12 @@ static int qc_waithand(struct qcam_device *q, int val)
                while (((status = read_lpstatus(q)) & 8))
                {
                        /* 1000 is enough spins on the I/O for all normal
-                          cases, at that point we start to poll slowly 
+                          cases, at that point we start to poll slowly
                           until the camera wakes up. However, we are
                           busy blocked until the camera responds, so
                           setting it lower is much better for interactive
                           response. */
-                          
+
                        if(runs++>maxpoll)
                        {
                                msleep_interruptible(5);
@@ -282,17 +282,17 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
 {
        unsigned int status;
        int runs=0;
-       
-       do 
+
+       do
        {
                status = read_lpdata(q);
                /* 1000 is enough spins on the I/O for all normal
-                  cases, at that point we start to poll slowly 
+                  cases, at that point we start to poll slowly
                   until the camera wakes up. However, we are
                   busy blocked until the camera responds, so
                   setting it lower is much better for interactive
                   response. */
-                  
+
                if(runs++>maxpoll)
                {
                        msleep_interruptible(5);
@@ -321,7 +321,7 @@ static int qc_detect(struct qcam_device *q)
 
        lastreg = reg = read_lpstatus(q) & 0xf0;
 
-       for (i = 0; i < 500; i++) 
+       for (i = 0; i < 500; i++)
        {
                reg = read_lpstatus(q) & 0xf0;
                if (reg != lastreg)
@@ -357,7 +357,7 @@ static int qc_detect(struct qcam_device *q)
 
 static void qc_reset(struct qcam_device *q)
 {
-       switch (q->port_mode & QC_FORCE_MASK) 
+       switch (q->port_mode & QC_FORCE_MASK)
        {
                case QC_FORCE_UNIDIR:
                        q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
@@ -370,7 +370,7 @@ static void qc_reset(struct qcam_device *q)
                case QC_ANY:
                        write_lpcontrol(q, 0x20);
                        write_lpdata(q, 0x75);
-       
+
                        if (read_lpdata(q) != 0x75) {
                                q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
                        } else {
@@ -398,8 +398,8 @@ static void qc_reset(struct qcam_device *q)
 static int qc_setscanmode(struct qcam_device *q)
 {
        int old_mode = q->mode;
-       
-       switch (q->transfer_scale) 
+
+       switch (q->transfer_scale)
        {
                case 1:
                        q->mode = 0;
@@ -412,7 +412,7 @@ static int qc_setscanmode(struct qcam_device *q)
                        break;
        }
 
-       switch (q->bpp) 
+       switch (q->bpp)
        {
                case 4:
                        break;
@@ -421,7 +421,7 @@ static int qc_setscanmode(struct qcam_device *q)
                        break;
        }
 
-       switch (q->port_mode & QC_MODE_MASK) 
+       switch (q->port_mode & QC_MODE_MASK)
        {
                case QC_BIDIR:
                        q->mode += 1;
@@ -430,10 +430,10 @@ static int qc_setscanmode(struct qcam_device *q)
                case QC_UNIDIR:
                        break;
        }
-       
+
        if (q->mode != old_mode)
                q->status |= QC_PARAM_CHANGE;
-       
+
        return 0;
 }
 
@@ -451,7 +451,7 @@ static void qc_set(struct qcam_device *q)
        /* Set the brightness.  Yes, this is repetitive, but it works.
         * Shorter versions seem to fail subtly.  Feel free to try :-). */
        /* I think the problem was in qc_command, not here -- bls */
-       
+
        qc_command(q, 0xb);
        qc_command(q, q->brightness);
 
@@ -502,13 +502,13 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
        unsigned int hi2, lo2;
        static int state = 0;
 
-       if (buffer == NULL) 
+       if (buffer == NULL)
        {
                state = 0;
                return 0;
        }
-       
-       switch (q->port_mode & QC_MODE_MASK) 
+
+       switch (q->port_mode & QC_MODE_MASK)
        {
                case QC_BIDIR:          /* Bi-directional Port */
                        write_lpcontrol(q, 0x26);
@@ -517,7 +517,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
                        write_lpcontrol(q, 0x2e);
                        lo2 = (qc_waithand2(q, 0) >> 1);
                        hi2 = (read_lpstatus(q) >> 3) & 0x1f;
-                       switch (q->bpp) 
+                       switch (q->bpp)
                        {
                                case 4:
                                        buffer[0] = lo & 0xf;
@@ -544,7 +544,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
                        write_lpcontrol(q, 0xe);
                        hi = (qc_waithand(q, 0) & 0xf0) >> 4;
 
-                       switch (q->bpp) 
+                       switch (q->bpp)
                        {
                                case 4:
                                        buffer[0] = lo;
@@ -552,7 +552,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
                                        ret = 2;
                                        break;
                                case 6:
-                                       switch (state) 
+                                       switch (state)
                                        {
                                                case 0:
                                                        buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
@@ -604,13 +604,13 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
        int  shift=8-q->bpp;
        char invert;
 
-       if (q->mode == -1) 
+       if (q->mode == -1)
                return -ENXIO;
 
        qc_command(q, 0x7);
        qc_command(q, q->mode);
 
-       if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) 
+       if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
        {
                write_lpcontrol(q, 0x2e);       /* turn port around */
                write_lpcontrol(q, 0x26);
@@ -618,7 +618,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
                write_lpcontrol(q, 0x2e);
                (void) qc_waithand(q, 0);
        }
-       
+
        /* strange -- should be 15:63 below, but 4bpp is odd */
        invert = (q->bpp == 4) ? 16 : 63;
 
@@ -629,15 +629,15 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
            q->transfer_scale;
        transperline = (transperline + divisor - 1) / divisor;
 
-       for (i = 0, yield = yieldlines; i < linestotrans; i++) 
+       for (i = 0, yield = yieldlines; i < linestotrans; i++)
        {
-               for (pixels_read = j = 0; j < transperline; j++) 
+               for (pixels_read = j = 0; j < transperline; j++)
                {
                        bytes = qc_readbytes(q, buffer);
-                       for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) 
+                       for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++)
                        {
                                int o;
-                               if (buffer[k] == 0 && invert == 16) 
+                               if (buffer[k] == 0 && invert == 16)
                                {
                                        /* 4bpp is odd (again) -- inverter is 16, not 15, but output
                                           must be 0-15 -- bls */
@@ -653,7 +653,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
                        pixels_read += bytes;
                }
                (void) qc_readbytes(q, NULL);   /* reset state machine */
-               
+
                /* Grabbing an entire frame from the quickcam is a lengthy
                   process. We don't (usually) want to busy-block the
                   processor for the entire frame. yieldlines is a module
@@ -666,7 +666,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
                }
        }
 
-       if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) 
+       if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
        {
                write_lpcontrol(q, 2);
                write_lpcontrol(q, 6);
@@ -687,7 +687,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct qcam_device *qcam=(struct qcam_device *)dev;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -762,7 +762,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        if(p->depth!=4 && p->depth!=6)
                                return -EINVAL;
-                       
+
                        /*
                         *      Now load the camera.
                         */
@@ -790,11 +790,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        if(vw->width<80||vw->width>320)
                                return -EINVAL;
-                               
+
                        qcam->width = 320;
                        qcam->height = 240;
                        qcam->transfer_scale = 4;
-                       
+
                        if(vw->width>=160 && vw->height>=120)
                        {
                                qcam->transfer_scale = 2;
@@ -808,11 +808,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                        mutex_lock(&qcam->lock);
                        qc_setscanmode(qcam);
                        mutex_unlock(&qcam->lock);
-                       
+
                        /* We must update the camera before we grab. We could
                           just have changed the grab size */
                        qcam->status |= QC_PARAM_CHANGE;
-                       
+
                        /* Ok we figured out what to use from our wide choice */
                        return 0;
                }
@@ -853,9 +853,9 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        struct qcam_device *qcam=(struct qcam_device *)v;
        int len;
        parport_claim_or_block(qcam->pdev);
-       
+
        mutex_lock(&qcam->lock);
-       
+
        qc_reset(qcam);
 
        /* Update the camera parameters if we need to */
@@ -863,13 +863,13 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
                qc_set(qcam);
 
        len=qc_capture(qcam, buf,count);
-       
+
        mutex_unlock(&qcam->lock);
-       
+
        parport_release(qcam->pdev);
        return len;
 }
+
 static struct file_operations qcam_fops = {
        .owner          = THIS_MODULE,
        .open           = video_exclusive_open,
@@ -905,11 +905,11 @@ static int init_bwqcam(struct parport *port)
        qcam=qcam_init(port);
        if(qcam==NULL)
                return -ENODEV;
-               
+
        parport_claim_or_block(qcam->pdev);
 
        qc_reset(qcam);
-       
+
        if(qc_detect(qcam)==0)
        {
                parport_release(qcam->pdev);
@@ -920,9 +920,9 @@ static int init_bwqcam(struct parport *port)
        qc_calibrate(qcam);
 
        parport_release(qcam->pdev);
-       
+
        printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
-       
+
        if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
        {
                parport_unregister_device(qcam->pdev);
@@ -1013,7 +1013,7 @@ static int __init init_bw_qcams(void)
                printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n");
                maxpoll = 5000;
        }
-       
+
        if (yieldlines < 1) {
                printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n");
                yieldlines = 1;
index 8211fd8d7cbfabc587f14cf7e99a19986e465ffc..22a7386bbea6f537b8f8b30dc32965ef5609fe7f 100644 (file)
@@ -16,7 +16,7 @@
  *
  * The parport parameter controls which parports will be scanned.
  * Scanning all parports causes some printers to print a garbage page.
- *       -- March 14, 1999  Billy Donahue <billy@escape.com> 
+ *       -- March 14, 1999  Billy Donahue <billy@escape.com>
  *
  * Fixed data format to BGR, added force_rgb parameter. Added missing
  * parport_unregister_driver() on module removal.
@@ -88,7 +88,7 @@ static inline unsigned int qcam_ready2(struct qcam_device *qcam)
        return (parport_read_data(qcam->pport) & 0x1)?1:0;
 }
 
-static unsigned int qcam_await_ready1(struct qcam_device *qcam, 
+static unsigned int qcam_await_ready1(struct qcam_device *qcam,
                                             int value)
 {
        unsigned long oldjiffies = jiffies;
@@ -98,7 +98,7 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
                if (qcam_ready1(qcam) == value)
                        return 0;
 
-       /* If the camera didn't respond within 1/25 second, poll slowly 
+       /* If the camera didn't respond within 1/25 second, poll slowly
           for a while. */
        for (i = 0; i < 50; i++)
        {
@@ -123,7 +123,7 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
                if (qcam_ready2(qcam) == value)
                        return 0;
 
-       /* If the camera didn't respond within 1/25 second, poll slowly 
+       /* If the camera didn't respond within 1/25 second, poll slowly
           for a while. */
        for (i = 0; i < 50; i++)
        {
@@ -157,12 +157,12 @@ static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
        unsigned int idata;
        parport_write_data(qcam->pport, data);
        idata = qcam_read_data(qcam);
-       if (data != idata) 
+       if (data != idata)
        {
-               printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, 
+               printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
                       idata);
                return 1;
-       } 
+       }
        return 0;
 }
 
@@ -193,12 +193,12 @@ static int qc_detect(struct qcam_device *qcam)
           no device was found".  Fix this one day. */
        if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
            && qcam->pport->probe_info[0].model
-           && !strcmp(qcam->pdev->port->probe_info[0].model, 
+           && !strcmp(qcam->pdev->port->probe_info[0].model,
                       "Color QuickCam 2.0")) {
                printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
                return 1;
        }
-       
+
        if (probe < 2)
                return 0;
 
@@ -206,11 +206,11 @@ static int qc_detect(struct qcam_device *qcam)
 
        /* look for a heartbeat */
        ostat = stat = parport_read_status(qcam->pport);
-       for (i=0; i<250; i++) 
+       for (i=0; i<250; i++)
        {
                mdelay(1);
                stat = parport_read_status(qcam->pport);
-               if (ostat != stat) 
+               if (ostat != stat)
                {
                        if (++count >= 3) return 1;
                        ostat = stat;
@@ -226,11 +226,11 @@ static int qc_detect(struct qcam_device *qcam)
        count = 0;
 
        ostat = stat = parport_read_status(qcam->pport);
-       for (i=0; i<250; i++) 
+       for (i=0; i<250; i++)
        {
                mdelay(1);
                stat = parport_read_status(qcam->pport);
-               if (ostat != stat) 
+               if (ostat != stat)
                {
                        if (++count >= 3) return 1;
                        ostat = stat;
@@ -247,7 +247,7 @@ static void qc_reset(struct qcam_device *qcam)
        parport_write_control(qcam->pport, 0x8);
        mdelay(1);
        parport_write_control(qcam->pport, 0xc);
-       mdelay(1);          
+       mdelay(1);
 }
 
 /* Reset the QuickCam and program for brightness, contrast,
@@ -258,7 +258,7 @@ static void qc_setup(struct qcam_device *q)
        qc_reset(q);
 
        /* Set the brightness.  */
-               qcam_set(q, 11, q->brightness);
+       qcam_set(q, 11, q->brightness);
 
        /* Set the height and width.  These refer to the actual
           CCD area *before* applying the selected decimation.  */
@@ -272,12 +272,12 @@ static void qc_setup(struct qcam_device *q)
        /* Set contrast and white balance.  */
        qcam_set(q, 0x19, q->contrast);
        qcam_set(q, 0x1f, q->whitebal);
-       
+
        /* Set the speed.  */
        qcam_set(q, 45, 2);
 }
 
-/* Read some bytes from the camera and put them in the buffer. 
+/* Read some bytes from the camera and put them in the buffer.
    nbytes should be a multiple of 3, because bidirectional mode gives
    us three bytes at a time.  */
 
@@ -383,7 +383,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
 
        if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
                return -EIO;
-       
+
        lines = q->height;
        pixelsperline = q->width;
        bitsperxfer = (is_bi_dir) ? 24 : 8;
@@ -499,7 +499,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct qcam_device *qcam=(struct qcam_device *)dev;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -574,7 +574,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                         */
                        if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
                                return -EINVAL;
-                       
+
                        /*
                         *      Now load the camera.
                         */
@@ -584,7 +584,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
 
                        mutex_lock(&qcam->lock);
                        parport_claim_or_block(qcam->pdev);
-                       qc_setup(qcam); 
+                       qc_setup(qcam);
                        parport_release(qcam->pdev);
                        mutex_unlock(&qcam->lock);
                        return 0;
@@ -601,11 +601,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        if(vw->width<80||vw->width>320)
                                return -EINVAL;
-                               
+
                        qcam->width = 80;
                        qcam->height = 60;
                        qcam->mode = QC_DECIMATION_4;
-                       
+
                        if(vw->width>=160 && vw->height>=120)
                        {
                                qcam->width = 160;
@@ -627,7 +627,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
                        }
 #endif
-                       /* Ok we figured out what to use from our 
+                       /* Ok we figured out what to use from our
                           wide choice */
                        mutex_lock(&qcam->lock);
                        parport_claim_or_block(qcam->pdev);
@@ -676,7 +676,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        mutex_lock(&qcam->lock);
        parport_claim_or_block(qcam->pdev);
        /* Probably should have a semaphore against multiple users */
-       len = qc_capture(qcam, buf,count); 
+       len = qc_capture(qcam, buf,count);
        parport_release(qcam->pdev);
        mutex_unlock(&qcam->lock);
        return len;
@@ -707,7 +707,7 @@ static struct video_device qcam_template=
 static struct qcam_device *qcam_init(struct parport *port)
 {
        struct qcam_device *q;
-       
+
        q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
        if(q==NULL)
                return NULL;
@@ -718,14 +718,14 @@ static struct qcam_device *qcam_init(struct parport *port)
 
        q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
 
-       if (q->pdev == NULL) 
+       if (q->pdev == NULL)
        {
                printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
                       port->name);
                kfree(q);
                return NULL;
        }
-       
+
        memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
 
        mutex_init(&q->lock);
@@ -766,11 +766,11 @@ static int init_cqcam(struct parport *port)
        qcam = qcam_init(port);
        if (qcam==NULL)
                return -ENODEV;
-               
+
        parport_claim_or_block(qcam->pdev);
 
        qc_reset(qcam);
-       
+
        if (probe && qc_detect(qcam)==0)
        {
                parport_release(qcam->pdev);
@@ -782,7 +782,7 @@ static int init_cqcam(struct parport *port)
        qc_setup(qcam);
 
        parport_release(qcam->pdev);
-       
+
        if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
        {
                printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
@@ -792,9 +792,9 @@ static int init_cqcam(struct parport *port)
                return -ENODEV;
        }
 
-       printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", 
+       printk(KERN_INFO "video%d: Colour QuickCam found on %s\n",
               qcam->vdev.minor, qcam->pport->name);
-       
+
        qcams[num_cams++] = qcam;
 
        return 0;
index 3cebfa91ca14ae4251fb869bc60f2fe2f9aa7f22..2227c5640c12c9552ade8b05d92cc9d8a7ad3234 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_  1 */  
+/* #define _CPIA_DEBUG_  1 */
 
 #include <linux/config.h>
 
@@ -67,11 +67,11 @@ MODULE_SUPPORTED_DEVICE("video");
 static unsigned short colorspace_conv = 0;
 module_param(colorspace_conv, ushort, 0444);
 MODULE_PARM_DESC(colorspace_conv,
-                 "\n<n> Colorspace conversion:"
-                 "\n0 = disable"
-                 "\n1 = enable"
-                 "\nDefault value is 0"
-                 "\n");
+                "\n<n> Colorspace conversion:"
+                "\n0 = disable"
+                "\n1 = enable"
+                "\nDefault value is 0"
+                "\n");
 
 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
 
@@ -189,8 +189,8 @@ enum {
 #define TC             94
 #define        EXP_ACC_DARK   50
 #define        EXP_ACC_LIGHT  90
-#define HIGH_COMP_102 160              
-#define MAX_COMP      239              
+#define HIGH_COMP_102 160
+#define MAX_COMP      239
 #define DARK_TIME       3
 #define LIGHT_TIME      3
 
@@ -208,7 +208,7 @@ static u8 flicker_jumps[2][2][4] =
 static void reset_camera_struct(struct cam_data *cam);
 static int find_over_exposure(int brightness);
 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
-                        int on);
+                       int on);
 
 
 /**********************************************************************
@@ -262,7 +262,7 @@ static void rvfree(void *mem, unsigned long size)
 static struct proc_dir_entry *cpia_proc_root=NULL;
 
 static int cpia_read_proc(char *page, char **start, off_t off,
-                          int count, int *eof, void *data)
+                         int count, int *eof, void *data)
 {
        char *out = page;
        int len, tmp;
@@ -276,58 +276,58 @@ static int cpia_read_proc(char *page, char **start, off_t off,
        out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
                       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
        out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
-                      cam->params.version.firmwareVersion,
-                      cam->params.version.firmwareRevision,
-                      cam->params.version.vcVersion,
-                      cam->params.version.vcRevision);
+                      cam->params.version.firmwareVersion,
+                      cam->params.version.firmwareRevision,
+                      cam->params.version.vcVersion,
+                      cam->params.version.vcRevision);
        out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
-                      cam->params.pnpID.vendor, cam->params.pnpID.product,
-                      cam->params.pnpID.deviceRevision);
+                      cam->params.pnpID.vendor, cam->params.pnpID.product,
+                      cam->params.pnpID.deviceRevision);
        out += sprintf(out, "VP-Version:               %d.%d %04x\n",
-                      cam->params.vpVersion.vpVersion,
-                      cam->params.vpVersion.vpRevision,
-                      cam->params.vpVersion.cameraHeadID);
-       
+                      cam->params.vpVersion.vpVersion,
+                      cam->params.vpVersion.vpRevision,
+                      cam->params.vpVersion.cameraHeadID);
+
        out += sprintf(out, "system_state:             %#04x\n",
-                      cam->params.status.systemState);
+                      cam->params.status.systemState);
        out += sprintf(out, "grab_state:               %#04x\n",
-                      cam->params.status.grabState);
+                      cam->params.status.grabState);
        out += sprintf(out, "stream_state:             %#04x\n",
-                      cam->params.status.streamState);
+                      cam->params.status.streamState);
        out += sprintf(out, "fatal_error:              %#04x\n",
-                      cam->params.status.fatalError);
+                      cam->params.status.fatalError);
        out += sprintf(out, "cmd_error:                %#04x\n",
-                      cam->params.status.cmdError);
+                      cam->params.status.cmdError);
        out += sprintf(out, "debug_flags:              %#04x\n",
-                      cam->params.status.debugFlags);
+                      cam->params.status.debugFlags);
        out += sprintf(out, "vp_status:                %#04x\n",
-                      cam->params.status.vpStatus);
+                      cam->params.status.vpStatus);
        out += sprintf(out, "error_code:               %#04x\n",
-                      cam->params.status.errorCode);
+                      cam->params.status.errorCode);
        /* QX3 specific entries */
        if (cam->params.qx3.qx3_detected) {
                out += sprintf(out, "button:                   %4d\n",
-                              cam->params.qx3.button);
+                              cam->params.qx3.button);
                out += sprintf(out, "cradled:                  %4d\n",
-                              cam->params.qx3.cradled);
+                              cam->params.qx3.cradled);
        }
        out += sprintf(out, "video_size:               %s\n",
-                      cam->params.format.videoSize == VIDEOSIZE_CIF ?
+                      cam->params.format.videoSize == VIDEOSIZE_CIF ?
                       "CIF " : "QCIF");
        out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
-                      cam->params.roi.colStart*8,
-                      cam->params.roi.rowStart*4,
-                      cam->params.roi.colEnd*8,
-                      cam->params.roi.rowEnd*4);
+                      cam->params.roi.colStart*8,
+                      cam->params.roi.rowStart*4,
+                      cam->params.roi.colEnd*8,
+                      cam->params.roi.rowEnd*4);
        out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
        out += sprintf(out, "transfer_rate:            %4dkB/s\n",
-                      cam->transfer_rate);
-       
+                      cam->transfer_rate);
+
        out += sprintf(out, "\nread-write\n");
        out += sprintf(out, "-----------------------  current       min"
-                      "       max   default  comment\n");
+                      "       max   default  comment\n");
        out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
-                      cam->params.colourParams.brightness, 0, 100, 50);
+                      cam->params.colourParams.brightness, 0, 100, 50);
        if (cam->params.version.firmwareVersion == 1 &&
           cam->params.version.firmwareRevision == 2)
                /* 1-02 firmware limits contrast to 80 */
@@ -336,26 +336,26 @@ static int cpia_read_proc(char *page, char **start, off_t off,
                tmp = 96;
 
        out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
-                      "  steps of 8\n",
-                      cam->params.colourParams.contrast, 0, tmp, 48);
+                      "  steps of 8\n",
+                      cam->params.colourParams.contrast, 0, tmp, 48);
        out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
-                      cam->params.colourParams.saturation, 0, 100, 50);
+                      cam->params.colourParams.saturation, 0, 100, 50);
        tmp = (25000+5000*cam->params.sensorFps.baserate)/
              (1<<cam->params.sensorFps.divisor);
        out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
-                      tmp/1000, tmp%1000, 3, 30, 15);
+                      tmp/1000, tmp%1000, 3, 30, 15);
        out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
-                      2*cam->params.streamStartLine, 0,
+                      2*cam->params.streamStartLine, 0,
                       cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
                       cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
        out += sprintf(out, "sub_sample:             %8s  %8s  %8s  %8s\n",
-                      cam->params.format.subSample == SUBSAMPLE_420 ?
+                      cam->params.format.subSample == SUBSAMPLE_420 ?
                       "420" : "422", "420", "422", "422");
        out += sprintf(out, "yuv_order:              %8s  %8s  %8s  %8s\n",
-                      cam->params.format.yuvOrder == YUVORDER_YUYV ?
+                      cam->params.format.yuvOrder == YUVORDER_YUYV ?
                       "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
        out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
-                      cam->params.ecpTiming ? "slow" : "normal", "slow",
+                      cam->params.ecpTiming ? "slow" : "normal", "slow",
                       "normal", "normal");
 
        if (cam->params.colourBalance.balanceMode == 2) {
@@ -366,11 +366,11 @@ static int cpia_read_proc(char *page, char **start, off_t off,
        out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
                       "  %8s\n",  tmpstr, "manual", "auto", "auto");
        out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
-                      cam->params.colourBalance.redGain, 0, 212, 32);
+                      cam->params.colourBalance.redGain, 0, 212, 32);
        out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
-                      cam->params.colourBalance.greenGain, 0, 212, 6);
+                      cam->params.colourBalance.greenGain, 0, 212, 6);
        out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
-                      cam->params.colourBalance.blueGain, 0, 212, 92);
+                      cam->params.colourBalance.blueGain, 0, 212, 92);
 
        if (cam->params.version.firmwareVersion == 1 &&
           cam->params.version.firmwareRevision == 2)
@@ -381,11 +381,11 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 
        if (cam->params.exposure.gainMode == 0)
                out += sprintf(out, "max_gain:                unknown  %28s"
-                              "  powers of 2\n", tmpstr); 
+                              "  powers of 2\n", tmpstr);
        else
                out += sprintf(out, "max_gain:               %8d  %28s"
                               "  1,2,4 or 8 \n",
-                              1<<(cam->params.exposure.gainMode-1), tmpstr);
+                              1<<(cam->params.exposure.gainMode-1), tmpstr);
 
        switch(cam->params.exposure.expMode) {
        case 1:
@@ -402,10 +402,10 @@ static int cpia_read_proc(char *page, char **start, off_t off,
        out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
                       "  %8s\n",  tmpstr, "manual", "auto", "auto");
        out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
-                      (2-cam->params.exposure.centreWeight) ? "on" : "off",
-                      "off", "on", "on");
+                      (2-cam->params.exposure.centreWeight) ? "on" : "off",
+                      "off", "on", "on");
        out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
-                      1<<cam->params.exposure.gain, 1, 1);
+                      1<<cam->params.exposure.gain, 1, 1);
        if (cam->params.version.firmwareVersion == 1 &&
           cam->params.version.firmwareRevision == 2)
                /* 1-02 firmware limits fineExp/2 to 127 */
@@ -414,7 +414,7 @@ static int cpia_read_proc(char *page, char **start, off_t off,
                tmp = 510;
 
        out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
-                      cam->params.exposure.fineExp*2, 0, tmp, 0);
+                      cam->params.exposure.fineExp*2, 0, tmp, 0);
        if (cam->params.version.firmwareVersion == 1 &&
           cam->params.version.firmwareRevision == 2)
                /* 1-02 firmware limits coarseExpHi to 0 */
@@ -426,46 +426,46 @@ static int cpia_read_proc(char *page, char **start, off_t off,
                       "  %8d\n", cam->params.exposure.coarseExpLo+
                       256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
        out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
-                      cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
+                      cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
        out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
-                      cam->params.exposure.green1Comp, COMP_GREEN1, 255,
+                      cam->params.exposure.green1Comp, COMP_GREEN1, 255,
                       COMP_GREEN1);
        out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
-                      cam->params.exposure.green2Comp, COMP_GREEN2, 255,
+                      cam->params.exposure.green2Comp, COMP_GREEN2, 255,
                       COMP_GREEN2);
        out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
-                      cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
-       
+                      cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
+
        out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
-                      cam->params.apcor.gain1, 0, 0xff, 0x1c);
+                      cam->params.apcor.gain1, 0, 0xff, 0x1c);
        out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
-                      cam->params.apcor.gain2, 0, 0xff, 0x1a);
+                      cam->params.apcor.gain2, 0, 0xff, 0x1a);
        out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
-                      cam->params.apcor.gain4, 0, 0xff, 0x2d);
+                      cam->params.apcor.gain4, 0, 0xff, 0x2d);
        out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
-                      cam->params.apcor.gain8, 0, 0xff, 0x2a);
+                      cam->params.apcor.gain8, 0, 0xff, 0x2a);
        out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
-                      cam->params.vlOffset.gain1, 0, 255, 24);
+                      cam->params.vlOffset.gain1, 0, 255, 24);
        out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
-                      cam->params.vlOffset.gain2, 0, 255, 28);
+                      cam->params.vlOffset.gain2, 0, 255, 28);
        out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
-                      cam->params.vlOffset.gain4, 0, 255, 30);
+                      cam->params.vlOffset.gain4, 0, 255, 30);
        out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
-                      cam->params.vlOffset.gain8, 0, 255, 30);
+                      cam->params.vlOffset.gain8, 0, 255, 30);
        out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
-                      cam->params.flickerControl.flickerMode ? "on" : "off",
+                      cam->params.flickerControl.flickerMode ? "on" : "off",
                       "off", "on", "off");
        out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
-                      " only 50/60\n",
-                      cam->mainsFreq ? 60 : 50, 50, 60, 50);
+                      " only 50/60\n",
+                      cam->mainsFreq ? 60 : 50, 50, 60, 50);
        if(cam->params.flickerControl.allowableOverExposure < 0)
                out += sprintf(out, "allowable_overexposure: %4dauto      auto  %8d      auto\n",
-                              -cam->params.flickerControl.allowableOverExposure,
-                              255);
+                              -cam->params.flickerControl.allowableOverExposure,
+                              255);
        else
                out += sprintf(out, "allowable_overexposure: %8d      auto  %8d      auto\n",
-                              cam->params.flickerControl.allowableOverExposure,
-                              255);
+                              cam->params.flickerControl.allowableOverExposure,
+                              255);
        out += sprintf(out, "compression_mode:       ");
        switch(cam->params.compression.mode) {
        case CPIA_COMPRESSION_NONE:
@@ -483,52 +483,52 @@ static int cpia_read_proc(char *page, char **start, off_t off,
        }
        out += sprintf(out, "    none,auto,manual      auto\n");
        out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
-                      cam->params.compression.decimation ==
-                      DECIMATION_ENAB ? "on":"off", "off", "on", 
+                      cam->params.compression.decimation ==
+                      DECIMATION_ENAB ? "on":"off", "off", "on",
                       "off");
        out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
-                      cam->params.compressionTarget.frTargeting  == 
+                      cam->params.compressionTarget.frTargeting  ==
                       CPIA_COMPRESSION_TARGET_FRAMERATE ?
                       "framerate":"quality",
                       "framerate", "quality", "quality");
        out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionTarget.targetFR, 1, 30, 15);
+                      cam->params.compressionTarget.targetFR, 1, 30, 15);
        out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionTarget.targetQ, 1, 64, 5);
+                      cam->params.compressionTarget.targetQ, 1, 64, 5);
        out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
-                      cam->params.yuvThreshold.yThreshold, 0, 31, 6);
+                      cam->params.yuvThreshold.yThreshold, 0, 31, 6);
        out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
-                      cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
+                      cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
        out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.hysteresis, 0, 255, 3);
+                      cam->params.compressionParams.hysteresis, 0, 255, 3);
        out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.threshMax, 0, 255, 11);
+                      cam->params.compressionParams.threshMax, 0, 255, 11);
        out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.smallStep, 0, 255, 1);
+                      cam->params.compressionParams.smallStep, 0, 255, 1);
        out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.largeStep, 0, 255, 3);
+                      cam->params.compressionParams.largeStep, 0, 255, 3);
        out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.decimationHysteresis,
+                      cam->params.compressionParams.decimationHysteresis,
                       0, 255, 2);
        out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.frDiffStepThresh,
+                      cam->params.compressionParams.frDiffStepThresh,
                       0, 255, 5);
        out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.qDiffStepThresh,
+                      cam->params.compressionParams.qDiffStepThresh,
                       0, 255, 3);
        out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
-                      cam->params.compressionParams.decimationThreshMod,
+                      cam->params.compressionParams.decimationThreshMod,
                       0, 255, 2);
        /* QX3 specific entries */
        if (cam->params.qx3.qx3_detected) {
-               out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
-                              cam->params.qx3.toplight ? "on" : "off",
+               out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n",
+                              cam->params.qx3.toplight ? "on" : "off",
                               "off", "on", "off");
-               out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
-                              cam->params.qx3.bottomlight ? "on" : "off",
+               out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n",
+                              cam->params.qx3.bottomlight ? "on" : "off",
                               "off", "on", "off");
        }
-       
+
        len = out - page;
        len -= off;
        if (len < count) {
@@ -543,7 +543,7 @@ static int cpia_read_proc(char *page, char **start, off_t off,
 
 
 static int match(char *checkstr, char **buffer, unsigned long *count,
-                 int *find_colon, int *err)
+                int *find_colon, int *err)
 {
        int ret, colon_found = 1;
        int len = strlen(checkstr);
@@ -583,7 +583,7 @@ static unsigned long int value(char **buffer, unsigned long *count, int *err)
 }
 
 static int cpia_write_proc(struct file *file, const char __user *buf,
-                           unsigned long count, void *data)
+                          unsigned long count, void *data)
 {
        struct cam_data *cam = data;
        struct cam_params new_params;
@@ -619,12 +619,12 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                retval = -EINVAL;
                goto out;
        }
-       
+
        buffer = page;
-       
+
        if (mutex_lock_interruptible(&cam->param_lock))
                return -ERESTARTSYS;
-       
+
        /*
         * Skip over leading whitespace
         */
@@ -632,15 +632,15 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                --count;
                ++buffer;
        }
-       
+
        memcpy(&new_params, &cam->params, sizeof(struct cam_params));
        new_mains = cam->mainsFreq;
-       
+
 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
 #define VALUE (value(&buffer,&count, &retval))
 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
-                               new_params.version.firmwareRevision == (y))
-       
+                              new_params.version.firmwareRevision == (y))
+
        retval = 0;
        while (count && !retval) {
                find_colon = 1;
@@ -656,7 +656,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                        }
                        command_flags |= COMMAND_SETCOLOURPARAMS;
                        if(new_params.flickerControl.allowableOverExposure < 0)
-                               new_params.flickerControl.allowableOverExposure = 
+                               new_params.flickerControl.allowableOverExposure =
                                        -find_over_exposure(new_params.colourParams.brightness);
                        if(new_params.flickerControl.flickerMode != 0)
                                command_flags |= COMMAND_SETFLICKERCTRL;
@@ -721,7 +721,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                                        /* Either base rate would work here */
                                        new_params.sensorFps.baserate = 1;
                                }
-                               new_params.flickerControl.coarseJump = 
+                               new_params.flickerControl.coarseJump =
                                        flicker_jumps[new_mains]
                                        [new_params.sensorFps.baserate]
                                        [new_params.sensorFps.divisor];
@@ -1085,7 +1085,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                } else if (MATCH("mains_frequency")) {
                        if (!retval && MATCH("50")) {
                                new_mains = 0;
-                               new_params.flickerControl.coarseJump = 
+                               new_params.flickerControl.coarseJump =
                                        flicker_jumps[new_mains]
                                        [new_params.sensorFps.baserate]
                                        [new_params.sensorFps.divisor];
@@ -1093,7 +1093,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                                        command_flags |= COMMAND_SETFLICKERCTRL;
                        } else if (!retval && MATCH("60")) {
                                new_mains = 1;
-                               new_params.flickerControl.coarseJump = 
+                               new_params.flickerControl.coarseJump =
                                        flicker_jumps[new_mains]
                                        [new_params.sensorFps.baserate]
                                        [new_params.sensorFps.divisor];
@@ -1103,7 +1103,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                                retval = -EINVAL;
                } else if (MATCH("allowable_overexposure")) {
                        if (!retval && MATCH("auto")) {
-                               new_params.flickerControl.allowableOverExposure = 
+                               new_params.flickerControl.allowableOverExposure =
                                        -find_over_exposure(new_params.colourParams.brightness);
                                if(new_params.flickerControl.flickerMode != 0)
                                        command_flags |= COMMAND_SETFLICKERCTRL;
@@ -1146,10 +1146,10 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                        command_flags |= COMMAND_SETCOMPRESSION;
                } else if (MATCH("compression_target")) {
                        if (!retval && MATCH("quality"))
-                               new_params.compressionTarget.frTargeting = 
+                               new_params.compressionTarget.frTargeting =
                                        CPIA_COMPRESSION_TARGET_QUALITY;
                        else if (!retval && MATCH("framerate"))
-                               new_params.compressionTarget.frTargeting = 
+                               new_params.compressionTarget.frTargeting =
                                        CPIA_COMPRESSION_TARGET_FRAMERATE;
                        else
                                retval = -EINVAL;
@@ -1173,7 +1173,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                        if (!retval) {
                                if(val > 0 && val <= 64)
                                        new_params.compressionTarget.targetQ = val;
-                               else 
+                               else
                                        retval = -EINVAL;
                        }
                        command_flags |= COMMAND_SETCOMPRESSIONTARGET;
@@ -1288,19 +1288,19 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                        }
                        command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
                } else if (MATCH("toplight")) {
-                       if (!retval && MATCH("on"))
+                       if (!retval && MATCH("on"))
                                new_params.qx3.toplight = 1;
                        else if (!retval && MATCH("off"))
                                new_params.qx3.toplight = 0;
-                       else 
+                       else
                                retval = -EINVAL;
                        command_flags |= COMMAND_SETLIGHTS;
                } else if (MATCH("bottomlight")) {
-                       if (!retval && MATCH("on"))
+                       if (!retval && MATCH("on"))
                                new_params.qx3.bottomlight = 1;
-                       else if (!retval && MATCH("off"))  
+                       else if (!retval && MATCH("off"))
                                new_params.qx3.bottomlight = 0;
-                       else 
+                       else
                                retval = -EINVAL;
                        command_flags |= COMMAND_SETLIGHTS;
                } else {
@@ -1326,7 +1326,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                        }
                }
        }
-#undef MATCH   
+#undef MATCH
 #undef VALUE
 #undef FIRMWARE_VERSION
        if (!retval) {
@@ -1349,24 +1349,24 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
                retval = size;
        } else
                DBG("error: %d\n", retval);
-       
+
        mutex_unlock(&cam->param_lock);
-       
+
 out:
        free_page((unsigned long)page);
-       return retval;
+       return retval;
 }
 
 static void create_proc_cpia_cam(struct cam_data *cam)
 {
        char name[7];
        struct proc_dir_entry *ent;
-       
+
        if (!cpia_proc_root || !cam)
                return;
 
        sprintf(name, "video%d", cam->vdev.minor);
-       
+
        ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
        if (!ent)
                return;
@@ -1374,9 +1374,9 @@ static void create_proc_cpia_cam(struct cam_data *cam)
        ent->data = cam;
        ent->read_proc = cpia_read_proc;
        ent->write_proc = cpia_write_proc;
-       /* 
+       /*
           size of the proc entry is 3736 bytes for the standard webcam;
-          the extra features of the QX3 microscope add 189 bytes.
+          the extra features of the QX3 microscope add 189 bytes.
           (we have not yet probed the camera to see which type it is).
        */
        ent->size = 3736 + 189;
@@ -1386,10 +1386,10 @@ static void create_proc_cpia_cam(struct cam_data *cam)
 static void destroy_proc_cpia_cam(struct cam_data *cam)
 {
        char name[7];
-       
+
        if (!cam || !cam->proc_entry)
                return;
-       
+
        sprintf(name, "video%d", cam->vdev.minor);
        remove_proc_entry(name, cpia_proc_root);
        cam->proc_entry = NULL;
@@ -1596,13 +1596,13 @@ static void set_vw_size(struct cam_data *cam)
                cam->vc.width = cam->vw.width;
        if(cam->vc.height == 0)
                cam->vc.height = cam->vw.height;
-       
+
        cam->params.roi.colStart += cam->vc.x >> 3;
        cam->params.roi.colEnd = cam->params.roi.colStart +
-                                (cam->vc.width >> 3);
+                                (cam->vc.width >> 3);
        cam->params.roi.rowStart += cam->vc.y >> 2;
        cam->params.roi.rowEnd = cam->params.roi.rowStart +
-                                (cam->vc.height >> 2);
+                                (cam->vc.height >> 2);
 
        return;
 }
@@ -1624,7 +1624,7 @@ static int allocate_frame_buf(struct cam_data *cam)
 static int free_frame_buf(struct cam_data *cam)
 {
        int i;
-       
+
        rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
        cam->frame_buf = NULL;
        for (i=0; i < FRAME_NUM; i++)
@@ -1667,7 +1667,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
                mutex_lock(&cam->param_lock);
                datasize=8;
                break;
-       case CPIA_COMMAND_ReadMCPorts: 
+       case CPIA_COMMAND_ReadMCPorts:
        case CPIA_COMMAND_ReadVCRegs:
                datasize = 4;
                break;
@@ -1746,10 +1746,10 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
                        mutex_unlock(&cam->param_lock);
                        break;
 
-               case CPIA_COMMAND_ReadMCPorts: 
-                       if (!cam->params.qx3.qx3_detected) 
+               case CPIA_COMMAND_ReadMCPorts:
+                       if (!cam->params.qx3.qx3_detected)
                                break;
-                       /* test button press */ 
+                       /* test button press */
                        cam->params.qx3.button = ((data[1] & 0x02) == 0);
                        if (cam->params.qx3.button) {
                                /* button pressed - unlock the latch */
@@ -1770,9 +1770,9 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
 
 /* send a command  to the camera with an additional data transaction */
 static int do_command_extended(struct cam_data *cam, u16 command,
-                               u8 a, u8 b, u8 c, u8 d,
-                               u8 e, u8 f, u8 g, u8 h,
-                               u8 i, u8 j, u8 k, u8 l)
+                              u8 a, u8 b, u8 c, u8 d,
+                              u8 e, u8 f, u8 g, u8 h,
+                              u8 i, u8 j, u8 k, u8 l)
 {
        int retval;
        u8 cmd[8], data[8];
@@ -1809,10 +1809,10 @@ static int do_command_extended(struct cam_data *cam, u16 command,
 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
 
 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
-                      int linesize, int mmap_kludge)
+                     int linesize, int mmap_kludge)
 {
        int y, u, v, r, g, b, y1;
-       
+
        /* Odd lines use the same u and v as the previous line.
         * Because of compression, it is necessary to get this
         * information from the decoded image. */
@@ -1925,7 +1925,7 @@ static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
 
 
 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
-                      int in_uyvy, int mmap_kludge)
+                     int in_uyvy, int mmap_kludge)
 {
        int y, u, v, r, g, b, y1;
 
@@ -2078,21 +2078,21 @@ static int parse_picture(struct cam_data *cam, int size)
                mutex_unlock(&cam->param_lock);
                return -1;
        }
-       
+
        if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
                LOG("illegal subtype %d\n",ibuf[17]);
                mutex_unlock(&cam->param_lock);
                return -1;
        }
        subsample_422 = ibuf[17] == SUBSAMPLE_422;
-       
+
        if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
                LOG("illegal yuvorder %d\n",ibuf[18]);
                mutex_unlock(&cam->param_lock);
                return -1;
        }
        in_uyvy = ibuf[18] == YUVORDER_UYVY;
-       
+
        if ((ibuf[24] != cam->params.roi.colStart) ||
            (ibuf[25] != cam->params.roi.colEnd) ||
            (ibuf[26] != cam->params.roi.rowStart) ||
@@ -2104,20 +2104,20 @@ static int parse_picture(struct cam_data *cam, int size)
        cols = 8*(ibuf[25] - ibuf[24]);
        rows = 4*(ibuf[27] - ibuf[26]);
 
-       
+
        if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
                LOG("illegal compression %d\n",ibuf[28]);
                mutex_unlock(&cam->param_lock);
                return -1;
        }
        compressed = (ibuf[28] == COMPRESSED);
-       
+
        if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
                LOG("illegal decimation %d\n",ibuf[29]);
                mutex_unlock(&cam->param_lock);
                return -1;
        }
-       decimation = (ibuf[29] == DECIMATION_ENAB);     
+       decimation = (ibuf[29] == DECIMATION_ENAB);
 
        cam->params.yuvThreshold.yThreshold = ibuf[30];
        cam->params.yuvThreshold.uvThreshold = ibuf[31];
@@ -2131,7 +2131,7 @@ static int parse_picture(struct cam_data *cam, int size)
        cam->params.status.errorCode = ibuf[39];
        cam->fps = ibuf[41];
        mutex_unlock(&cam->param_lock);
-       
+
        linesize = skipcount(cols, out_fmt);
        ibuf += FRAME_HEADER_SIZE;
        size -= FRAME_HEADER_SIZE;
@@ -2150,14 +2150,14 @@ static int parse_picture(struct cam_data *cam, int size)
                        if (!compressed || (compressed && !(*ibuf & 1))) {
                                if(subsample_422 || even_line) {
                                obuf += yuvconvert(ibuf, obuf, out_fmt,
-                                                  in_uyvy, cam->mmap_kludge);
+                                                  in_uyvy, cam->mmap_kludge);
                                ibuf += 4;
                                ll -= 4;
                        } else {
                                        /* SUBSAMPLE_420 on an odd line */
                                        obuf += convert420(ibuf, obuf,
-                                                          out_fmt, linesize,
-                                                          cam->mmap_kludge);
+                                                          out_fmt, linesize,
+                                                          cam->mmap_kludge);
                                        ibuf += 2;
                                        ll -= 2;
                                }
@@ -2183,7 +2183,7 @@ static int parse_picture(struct cam_data *cam, int size)
 
                        if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
                           (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
-                               size -= 4;
+                               size -= 4;
                                break;
                        }
 
@@ -2204,7 +2204,7 @@ static int parse_picture(struct cam_data *cam, int size)
                        return -1;
                }
        }
-       
+
        if(decimation) {
                /* interpolate odd rows */
                int i, j;
@@ -2233,7 +2233,7 @@ static int parse_picture(struct cam_data *cam, int size)
 static inline int init_stream_cap(struct cam_data *cam)
 {
        return do_command(cam, CPIA_COMMAND_InitStreamCap,
-                         0, cam->params.streamStartLine, 0, 0);
+                         0, cam->params.streamStartLine, 0, 0);
 }
 
 
@@ -2254,7 +2254,7 @@ static int find_over_exposure(int brightness)
        int MaxAllowableOverExposure, OverExposure;
 
        MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
-                                  FLICKER_BRIGHTNESS_CONSTANT;
+                                  FLICKER_BRIGHTNESS_CONSTANT;
 
        if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
                OverExposure = MaxAllowableOverExposure;
@@ -2280,62 +2280,62 @@ static void dispatch_commands(struct cam_data *cam)
        DEB_BYTE(cam->cmd_queue>>8);
        if (cam->cmd_queue & COMMAND_SETFORMAT) {
                do_command(cam, CPIA_COMMAND_SetFormat,
-                          cam->params.format.videoSize,
-                          cam->params.format.subSample,
-                          cam->params.format.yuvOrder, 0);
+                          cam->params.format.videoSize,
+                          cam->params.format.subSample,
+                          cam->params.format.yuvOrder, 0);
                do_command(cam, CPIA_COMMAND_SetROI,
-                          cam->params.roi.colStart, cam->params.roi.colEnd,
-                          cam->params.roi.rowStart, cam->params.roi.rowEnd);
+                          cam->params.roi.colStart, cam->params.roi.colEnd,
+                          cam->params.roi.rowStart, cam->params.roi.rowEnd);
                cam->first_frame = 1;
        }
 
        if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
                do_command(cam, CPIA_COMMAND_SetColourParams,
-                          cam->params.colourParams.brightness,
-                          cam->params.colourParams.contrast,
-                          cam->params.colourParams.saturation, 0);
+                          cam->params.colourParams.brightness,
+                          cam->params.colourParams.contrast,
+                          cam->params.colourParams.saturation, 0);
 
        if (cam->cmd_queue & COMMAND_SETAPCOR)
                do_command(cam, CPIA_COMMAND_SetApcor,
-                          cam->params.apcor.gain1,
-                          cam->params.apcor.gain2,
-                          cam->params.apcor.gain4,
-                          cam->params.apcor.gain8);
+                          cam->params.apcor.gain1,
+                          cam->params.apcor.gain2,
+                          cam->params.apcor.gain4,
+                          cam->params.apcor.gain8);
 
        if (cam->cmd_queue & COMMAND_SETVLOFFSET)
                do_command(cam, CPIA_COMMAND_SetVLOffset,
-                          cam->params.vlOffset.gain1,
-                          cam->params.vlOffset.gain2,
-                          cam->params.vlOffset.gain4,
-                          cam->params.vlOffset.gain8);
+                          cam->params.vlOffset.gain1,
+                          cam->params.vlOffset.gain2,
+                          cam->params.vlOffset.gain4,
+                          cam->params.vlOffset.gain8);
 
        if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
                do_command_extended(cam, CPIA_COMMAND_SetExposure,
-                                   cam->params.exposure.gainMode,
-                                   1,
-                                   cam->params.exposure.compMode,
-                                   cam->params.exposure.centreWeight,
-                                   cam->params.exposure.gain,
-                                   cam->params.exposure.fineExp,
-                                   cam->params.exposure.coarseExpLo,
-                                   cam->params.exposure.coarseExpHi,
-                                   cam->params.exposure.redComp,
-                                   cam->params.exposure.green1Comp,
-                                   cam->params.exposure.green2Comp,
-                                   cam->params.exposure.blueComp);
+                                   cam->params.exposure.gainMode,
+                                   1,
+                                   cam->params.exposure.compMode,
+                                   cam->params.exposure.centreWeight,
+                                   cam->params.exposure.gain,
+                                   cam->params.exposure.fineExp,
+                                   cam->params.exposure.coarseExpLo,
+                                   cam->params.exposure.coarseExpHi,
+                                   cam->params.exposure.redComp,
+                                   cam->params.exposure.green1Comp,
+                                   cam->params.exposure.green2Comp,
+                                   cam->params.exposure.blueComp);
                if(cam->params.exposure.expMode != 1) {
                        do_command_extended(cam, CPIA_COMMAND_SetExposure,
-                                           0,
-                                           cam->params.exposure.expMode,
-                                           0, 0,
-                                           cam->params.exposure.gain,
-                                           cam->params.exposure.fineExp,
-                                           cam->params.exposure.coarseExpLo,
-                                           cam->params.exposure.coarseExpHi,
-                                           0, 0, 0, 0);
+                                           0,
+                                           cam->params.exposure.expMode,
+                                           0, 0,
+                                           cam->params.exposure.gain,
+                                           cam->params.exposure.fineExp,
+                                           cam->params.exposure.coarseExpLo,
+                                           cam->params.exposure.coarseExpHi,
+                                           0, 0, 0, 0);
                }
        }
-       
+
        if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
                if (cam->params.colourBalance.balanceMode == 1) {
                        do_command(cam, CPIA_COMMAND_SetColourBalance,
@@ -2358,47 +2358,47 @@ static void dispatch_commands(struct cam_data *cam)
 
        if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
                do_command(cam, CPIA_COMMAND_SetCompressionTarget,
-                          cam->params.compressionTarget.frTargeting,
-                          cam->params.compressionTarget.targetFR,
-                          cam->params.compressionTarget.targetQ, 0);
+                          cam->params.compressionTarget.frTargeting,
+                          cam->params.compressionTarget.targetFR,
+                          cam->params.compressionTarget.targetQ, 0);
 
        if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
                do_command(cam, CPIA_COMMAND_SetYUVThresh,
-                          cam->params.yuvThreshold.yThreshold,
-                          cam->params.yuvThreshold.uvThreshold, 0, 0);
+                          cam->params.yuvThreshold.yThreshold,
+                          cam->params.yuvThreshold.uvThreshold, 0, 0);
 
        if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
                do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
-                           0, 0, 0, 0,
-                           cam->params.compressionParams.hysteresis,
-                           cam->params.compressionParams.threshMax,
-                           cam->params.compressionParams.smallStep,
-                           cam->params.compressionParams.largeStep,
-                           cam->params.compressionParams.decimationHysteresis,
-                           cam->params.compressionParams.frDiffStepThresh,
-                           cam->params.compressionParams.qDiffStepThresh,
-                           cam->params.compressionParams.decimationThreshMod);
+                           0, 0, 0, 0,
+                           cam->params.compressionParams.hysteresis,
+                           cam->params.compressionParams.threshMax,
+                           cam->params.compressionParams.smallStep,
+                           cam->params.compressionParams.largeStep,
+                           cam->params.compressionParams.decimationHysteresis,
+                           cam->params.compressionParams.frDiffStepThresh,
+                           cam->params.compressionParams.qDiffStepThresh,
+                           cam->params.compressionParams.decimationThreshMod);
 
        if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
                do_command(cam, CPIA_COMMAND_SetCompression,
-                          cam->params.compression.mode,
+                          cam->params.compression.mode,
                           cam->params.compression.decimation, 0, 0);
 
        if (cam->cmd_queue & COMMAND_SETSENSORFPS)
                do_command(cam, CPIA_COMMAND_SetSensorFPS,
-                          cam->params.sensorFps.divisor,
-                          cam->params.sensorFps.baserate, 0, 0);
+                          cam->params.sensorFps.divisor,
+                          cam->params.sensorFps.baserate, 0, 0);
 
        if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
                do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
-                          cam->params.flickerControl.flickerMode,
-                          cam->params.flickerControl.coarseJump,
-                          abs(cam->params.flickerControl.allowableOverExposure),
-                          0);
+                          cam->params.flickerControl.flickerMode,
+                          cam->params.flickerControl.coarseJump,
+                          abs(cam->params.flickerControl.allowableOverExposure),
+                          0);
 
        if (cam->cmd_queue & COMMAND_SETECPTIMING)
                do_command(cam, CPIA_COMMAND_SetECPTiming,
-                          cam->params.ecpTiming, 0, 0, 0);
+                          cam->params.ecpTiming, 0, 0, 0);
 
        if (cam->cmd_queue & COMMAND_PAUSE)
                do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
@@ -2409,9 +2409,9 @@ static void dispatch_commands(struct cam_data *cam)
        if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
          {
            int p1 = (cam->params.qx3.bottomlight == 0) << 1;
-            int p2 = (cam->params.qx3.toplight == 0) << 3;
-            do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
-            do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+           int p2 = (cam->params.qx3.toplight == 0) << 3;
+           do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
+           do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
          }
 
        cam->cmd_queue = COMMAND_NONE;
@@ -2422,11 +2422,11 @@ static void dispatch_commands(struct cam_data *cam)
 
 
 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
-                        int on)
+                       int on)
 {
        /* Everything in here is from the Windows driver */
 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
-                               params->version.firmwareRevision == (y))
+                              params->version.firmwareRevision == (y))
 /* define for compgain calculation */
 #if 0
 #define COMPGAIN(base, curexp, newexp) \
@@ -2441,7 +2441,7 @@ static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
      (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
 #endif
 
+
        int currentexp = params->exposure.coarseExpLo +
                         params->exposure.coarseExpHi*256;
        int startexp;
@@ -2482,7 +2482,7 @@ static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
                }
                if(FIRMWARE_VERSION(1,2))
                        params->exposure.compMode = 0;
-               else 
+               else
                        params->exposure.compMode = 1;
 
                params->apcor.gain1 = 0x18;
@@ -2533,14 +2533,14 @@ static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
 }
 
 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
-                               cam->params.version.firmwareRevision == (y))
+                              cam->params.version.firmwareRevision == (y))
 /* monitor the exposure and adjust the sensor frame rate if needed */
 static void monitor_exposure(struct cam_data *cam)
 {
        u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
        int retval, light_exp, dark_exp, very_dark_exp;
        int old_exposure, new_exposure, framerate;
-       
+
        /* get necessary stats and register settings from camera */
        /* do_command can't handle this, so do it ourselves */
        cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
@@ -2564,17 +2564,17 @@ static void monitor_exposure(struct cam_data *cam)
 
        mutex_lock(&cam->param_lock);
        light_exp = cam->params.colourParams.brightness +
-                   TC - 50 + EXP_ACC_LIGHT;
+                   TC - 50 + EXP_ACC_LIGHT;
        if(light_exp > 255)
                light_exp = 255;
        dark_exp = cam->params.colourParams.brightness +
-                  TC - 50 - EXP_ACC_DARK;
+                  TC - 50 - EXP_ACC_DARK;
        if(dark_exp < 0)
                dark_exp = 0;
        very_dark_exp = dark_exp/2;
-       
+
        old_exposure = cam->params.exposure.coarseExpHi * 256 +
-                      cam->params.exposure.coarseExpLo;
+                      cam->params.exposure.coarseExpLo;
 
        if(!cam->params.flickerControl.disabled) {
                /* Flicker control on */
@@ -2667,11 +2667,11 @@ static void monitor_exposure(struct cam_data *cam)
                        cam->exposure_status = EXPOSURE_NORMAL;
                }
        }
-       
+
        framerate = cam->fps;
        if(framerate > 30 || framerate < 1)
                framerate = 1;
-       
+
        if(!cam->params.flickerControl.disabled) {
                /* Flicker control on */
                if((cam->exposure_status == EXPOSURE_VERY_DARK ||
@@ -2683,10 +2683,10 @@ static void monitor_exposure(struct cam_data *cam)
                        ++cam->params.sensorFps.divisor;
                        cam->cmd_queue |= COMMAND_SETSENSORFPS;
 
-                       cam->params.flickerControl.coarseJump = 
+                       cam->params.flickerControl.coarseJump =
                                flicker_jumps[cam->mainsFreq]
-                                            [cam->params.sensorFps.baserate]
-                                            [cam->params.sensorFps.divisor];
+                                            [cam->params.sensorFps.baserate]
+                                            [cam->params.sensorFps.divisor];
                        cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
 
                        new_exposure = cam->params.flickerControl.coarseJump-1;
@@ -2704,15 +2704,15 @@ static void monitor_exposure(struct cam_data *cam)
                   cam->params.sensorFps.divisor > 0) {
 
                        /* light for too long */
-                       int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ; 
+                       int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
 
                        --cam->params.sensorFps.divisor;
                        cam->cmd_queue |= COMMAND_SETSENSORFPS;
 
-                       cam->params.flickerControl.coarseJump = 
+                       cam->params.flickerControl.coarseJump =
                                flicker_jumps[cam->mainsFreq]
-                                            [cam->params.sensorFps.baserate]
-                                            [cam->params.sensorFps.divisor];
+                                            [cam->params.sensorFps.baserate]
+                                            [cam->params.sensorFps.divisor];
                        cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
 
                        new_exposure = cam->params.flickerControl.coarseJump-1;
@@ -2772,7 +2772,7 @@ static void monitor_exposure(struct cam_data *cam)
 
    It also adjust the colour balance when an exposure step is detected - as
    long as flicker is running
-*/   
+*/
 static void restart_flicker(struct cam_data *cam)
 {
        int cam_exposure, old_exp;
@@ -2786,22 +2786,22 @@ static void restart_flicker(struct cam_data *cam)
        }
        cam_exposure = cam->raw_image[39]*2;
        old_exp = cam->params.exposure.coarseExpLo +
-                 cam->params.exposure.coarseExpHi*256;
-       /* 
-         see how far away camera exposure is from a valid 
-         flicker exposure value
-       */
-       cam_exposure %= cam->params.flickerControl.coarseJump;
+                 cam->params.exposure.coarseExpHi*256;
+       /*
+         see how far away camera exposure is from a valid
+         flicker exposure value
+       */
+       cam_exposure %= cam->params.flickerControl.coarseJump;
        if(!cam->params.flickerControl.disabled &&
-          cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
+          cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
                /* Flicker control auto-disabled */
                cam->params.flickerControl.disabled = 1;
        }
-       
+
        if(cam->params.flickerControl.disabled &&
           cam->params.flickerControl.flickerMode &&
           old_exp > cam->params.flickerControl.coarseJump +
-                    ROUND_UP_EXP_FOR_FLICKER) {
+                    ROUND_UP_EXP_FOR_FLICKER) {
                /* exposure is now high enough to switch
                   flicker control back on */
                set_flicker(&cam->params, &cam->cmd_queue, 1);
@@ -2818,7 +2818,7 @@ static int clear_stall(struct cam_data *cam)
 {
        /* FIXME: Does this actually work? */
        LOG("Clearing stall\n");
-       
+
        cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
        do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
        return cam->params.status.streamState != STREAM_PAUSED;
@@ -2878,7 +2878,7 @@ static int fetch_frame(void *data)
                                        return -EINTR;
 
                                do_command(cam, CPIA_COMMAND_GetCameraStatus,
-                                          0, 0, 0, 0);
+                                          0, 0, 0, 0);
                        }
                        if(cam->params.status.streamState != STREAM_READY) {
                                continue;
@@ -2903,18 +2903,18 @@ static int fetch_frame(void *data)
 
                /* Switch flicker control back on if it got turned off */
                restart_flicker(cam);
-               
+
                /* If AEC is enabled, monitor the exposure and
                   adjust the sensor frame rate if needed */
                if(cam->params.exposure.expMode == 2)
                        monitor_exposure(cam);
-               
+
                /* camera idle now so dispatch queued commands */
                dispatch_commands(cam);
 
                /* Update our knowledge of the camera state */
-               do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
-               do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+               do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+               do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
                do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
 
                /* decompress and convert image to by copying it from
@@ -2933,7 +2933,7 @@ static int fetch_frame(void *data)
                                   uncompressed. */
                                cam->first_frame = 1;
                                do_command(cam, CPIA_COMMAND_SetGrabMode,
-                                          CPIA_GRAB_SINGLE, 0, 0, 0);
+                                          CPIA_GRAB_SINGLE, 0, 0, 0);
                                /* FIXME: Trial & error - need up to 70ms for
                                   the grab mode change to complete ? */
                                msleep_interruptible(70);
@@ -2957,12 +2957,12 @@ static int fetch_frame(void *data)
                if (cam->first_frame) {
                        cam->first_frame = 0;
                        do_command(cam, CPIA_COMMAND_SetCompression,
-                                  cam->params.compression.mode,
+                                  cam->params.compression.mode,
                                   cam->params.compression.decimation, 0, 0);
 
                        /* Switch from single-grab to continuous grab */
                        do_command(cam, CPIA_COMMAND_SetGrabMode,
-                                  CPIA_GRAB_CONTINUOUS, 0, 0, 0);
+                                  CPIA_GRAB_CONTINUOUS, 0, 0, 0);
                }
                return 0;
        }
@@ -2977,12 +2977,12 @@ static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
                if ((err = allocate_frame_buf(cam)))
                        return err;
        }
-       
+
        cam->curframe = vm->frame;
        cam->frame[cam->curframe].state = FRAME_READY;
        return fetch_frame(cam);
 }
-  
+
 static int goto_high_power(struct cam_data *cam)
 {
        if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
@@ -3039,22 +3039,22 @@ static void save_camera_state(struct cam_data *cam)
 static int set_camera_state(struct cam_data *cam)
 {
        cam->cmd_queue = COMMAND_SETCOMPRESSION |
-                        COMMAND_SETCOMPRESSIONTARGET |
-                        COMMAND_SETCOLOURPARAMS |
-                        COMMAND_SETFORMAT |
-                        COMMAND_SETYUVTHRESH |
-                        COMMAND_SETECPTIMING |
-                        COMMAND_SETCOMPRESSIONPARAMS |
-                        COMMAND_SETEXPOSURE |
-                        COMMAND_SETCOLOURBALANCE |
-                        COMMAND_SETSENSORFPS |
-                        COMMAND_SETAPCOR |
-                        COMMAND_SETFLICKERCTRL |
-                        COMMAND_SETVLOFFSET;
+                        COMMAND_SETCOMPRESSIONTARGET |
+                        COMMAND_SETCOLOURPARAMS |
+                        COMMAND_SETFORMAT |
+                        COMMAND_SETYUVTHRESH |
+                        COMMAND_SETECPTIMING |
+                        COMMAND_SETCOMPRESSIONPARAMS |
+                        COMMAND_SETEXPOSURE |
+                        COMMAND_SETCOLOURBALANCE |
+                        COMMAND_SETSENSORFPS |
+                        COMMAND_SETAPCOR |
+                        COMMAND_SETFLICKERCTRL |
+                        COMMAND_SETVLOFFSET;
 
        do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
        dispatch_commands(cam);
-       
+
        /* Wait 6 frames for the sensor to get all settings and
           AEC/ACB to settle */
        msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
@@ -3062,7 +3062,7 @@ static int set_camera_state(struct cam_data *cam)
 
        if(signal_pending(current))
                return -EINTR;
-       
+
        save_camera_state(cam);
 
        return 0;
@@ -3094,9 +3094,9 @@ static int reset_camera(struct cam_data *cam)
                if (goto_low_power(cam))
                        return -ENODEV;
        }
-       
+
        /* procedure described in developer's guide p3-28 */
-       
+
        /* Check the firmware version. */
        cam->params.version.firmwareVersion = 0;
        get_version_information(cam);
@@ -3113,14 +3113,14 @@ static int reset_camera(struct cam_data *cam)
        cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
                                        cam->params.pnpID.product == 0x0001);
 
-       /* The fatal error checking should be done after
+       /* The fatal error checking should be done after
         * the camera powers up (developer's guide p 3-38) */
 
        /* Set streamState before transition to high power to avoid bug
         * in firmware 1-02 */
        do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
-                  STREAM_NOT_READY, 0);
-       
+                  STREAM_NOT_READY, 0);
+
        /* GotoHiPower */
        err = goto_high_power(cam);
        if (err)
@@ -3142,16 +3142,16 @@ static int reset_camera(struct cam_data *cam)
                        /* Firmware 1-02 may do this for parallel port cameras,
                         * just clear the flags (developer's guide p 3-38) */
                        do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
-                                  FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
+                                  FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
                }
        }
-       
+
        /* Check the camera status again */
        if (cam->params.status.fatalError) {
                if (cam->params.status.fatalError)
                        return -EIO;
        }
-       
+
        /* VPVersion can't be retrieved before the camera is in HiPower,
         * so get it here instead of in get_version_information. */
        do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
@@ -3193,24 +3193,24 @@ static int cpia_open(struct inode *inode, struct file *file)
                if (!cam->raw_image)
                        goto oops;
        }
-       
+
        if (!cam->decompressed_frame.data) {
                cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
                if (!cam->decompressed_frame.data)
                        goto oops;
        }
-       
+
        /* open cpia */
        err = -ENODEV;
        if (cam->ops->open(cam->lowlevel_data))
                goto oops;
-       
+
        /* reset the camera */
        if ((err = reset_camera(cam)) != 0) {
                cam->ops->close(cam->lowlevel_data);
                goto oops;
        }
-       
+
        err = -EINTR;
        if(signal_pending(current))
                goto oops;
@@ -3224,7 +3224,7 @@ static int cpia_open(struct inode *inode, struct file *file)
 
        /* init it to something */
        cam->mmap_kludge = 0;
-       
+
        ++cam->open_count;
        file->private_data = dev;
        mutex_unlock(&cam->busy_lock);
@@ -3250,10 +3250,10 @@ static int cpia_close(struct inode *inode, struct file *file)
        struct cam_data *cam = dev->priv;
 
        if (cam->ops) {
-               /* Return ownership of /proc/cpia/videoX to root */
+               /* Return ownership of /proc/cpia/videoX to root */
                if(cam->proc_entry)
                        cam->proc_entry->uid = 0;
-       
+
                /* save camera state for later open (developers guide ch 3.5.3) */
                save_camera_state(cam);
 
@@ -3342,7 +3342,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
                return -EFAULT;
        }
        if (copy_to_user(buf, cam->decompressed_frame.data,
-                       cam->decompressed_frame.count)) {
+                       cam->decompressed_frame.count)) {
                DBG("copy_to_user failed\n");
                mutex_unlock(&cam->busy_lock);
                return -EFAULT;
@@ -3361,7 +3361,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
        if (!cam || !cam->ops)
                return -ENODEV;
-       
+
        /* make this _really_ smp-safe */
        if (mutex_lock_interruptible(&cam->busy_lock))
                return -EINTR;
@@ -3405,7 +3405,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                v->norm = 0;
                break;
        }
-       
+
        case VIDIOCSCHAN:
        {
                struct video_channel *v = arg;
@@ -3424,7 +3424,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                *pic = cam->vp;
                break;
        }
-       
+
        case VIDIOCSPICT:
        {
                struct video_picture *vp = arg;
@@ -3458,11 +3458,11 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
                /* Adjust flicker control if necessary */
                if(cam->params.flickerControl.allowableOverExposure < 0)
-                       cam->params.flickerControl.allowableOverExposure = 
+                       cam->params.flickerControl.allowableOverExposure =
                                -find_over_exposure(cam->params.colourParams.brightness);
                if(cam->params.flickerControl.flickerMode != 0)
                        cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-               
+
 
                /* queue command to update camera */
                cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
@@ -3482,7 +3482,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                *vw = cam->vw;
                break;
        }
-       
+
        case VIDIOCSWIN:
        {
                /* copy_from_user, check validity, copy to internal structure */
@@ -3514,7 +3514,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
                        /* video size is changing, reset the subcapture area */
                        memset(&cam->vc, 0, sizeof(cam->vc));
-                       
+
                        set_vw_size(cam);
                        DBG("%d / %d\n", cam->vw.width, cam->vw.height);
                        cam->cmd_queue |= COMMAND_SETFORMAT;
@@ -3547,7 +3547,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                        vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
                break;
        }
-       
+
        case VIDIOCMCAPTURE:
        {
                struct video_mmap *vm = arg;
@@ -3597,7 +3597,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
                        /* video size is changing, reset the subcapture area */
                        memset(&cam->vc, 0, sizeof(cam->vc));
-                       
+
                        set_vw_size(cam);
                        cam->cmd_queue |= COMMAND_SETFORMAT;
                        dispatch_commands(cam);
@@ -3608,7 +3608,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
                break;
        }
-       
+
        case VIDIOCSYNC:
        {
                int *frame = arg;
@@ -3649,7 +3649,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                *vc = cam->vc;
 
                break;
-       }       
+       }
 
        case VIDIOCSCAPTURE:
        {
@@ -3665,7 +3665,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                        retval = -EINVAL;
                        break;
                }
-               
+
                /* Clip to the resolution we can set for the ROI
                   (every 8 columns and 4 rows) */
                vc->x      = vc->x      & ~(__u32)7;
@@ -3681,14 +3681,14 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                }
 
                DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
-               
+
                mutex_lock(&cam->param_lock);
-               
+
                cam->vc.x      = vc->x;
                cam->vc.y      = vc->y;
                cam->vc.width  = vc->width;
                cam->vc.height = vc->height;
-               
+
                set_vw_size(cam);
                cam->cmd_queue |= COMMAND_SETFORMAT;
 
@@ -3699,7 +3699,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                dispatch_commands(cam);
                break;
        }
-       
+
        case VIDIOCGUNIT:
        {
                struct video_unit *vu = arg;
@@ -3715,7 +3715,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
-               
+
        /* pointless to implement overlay with this camera */
        case VIDIOCCAPTURE:
        case VIDIOCGFBUF:
@@ -3738,7 +3738,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
        mutex_unlock(&cam->busy_lock);
        return retval;
-} 
+}
 
 static int cpia_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
@@ -3759,7 +3759,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
 
        if (!cam || !cam->ops)
                return -ENODEV;
-       
+
        DBG("cpia_mmap: %ld\n", size);
 
        if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
@@ -3767,7 +3767,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
 
        if (!cam || !cam->ops)
                return -ENODEV;
-       
+
        /* make this _really_ smp-safe */
        if (mutex_lock_interruptible(&cam->busy_lock))
                return -EINTR;
@@ -3851,11 +3851,11 @@ static void reset_camera_struct(struct cam_data *cam)
        cam->params.flickerControl.flickerMode = 0;
        cam->params.flickerControl.disabled = 1;
 
-       cam->params.flickerControl.coarseJump = 
+       cam->params.flickerControl.coarseJump =
                flicker_jumps[cam->mainsFreq]
-                            [cam->params.sensorFps.baserate]
-                            [cam->params.sensorFps.divisor];
-       cam->params.flickerControl.allowableOverExposure = 
+                            [cam->params.sensorFps.baserate]
+                            [cam->params.sensorFps.divisor];
+       cam->params.flickerControl.allowableOverExposure =
                -find_over_exposure(cam->params.colourParams.brightness);
        cam->params.vlOffset.gain1 = 20;
        cam->params.vlOffset.gain2 = 24;
@@ -3870,21 +3870,21 @@ static void reset_camera_struct(struct cam_data *cam)
        cam->params.compressionParams.qDiffStepThresh = 3;
        cam->params.compressionParams.decimationThreshMod = 2;
        /* End of default values from Software Developer's Guide */
-       
+
        cam->transfer_rate = 0;
        cam->exposure_status = EXPOSURE_NORMAL;
-       
+
        /* Set Sensor FPS to 15fps. This seems better than 30fps
         * for indoor lighting. */
        cam->params.sensorFps.divisor = 1;
        cam->params.sensorFps.baserate = 1;
-       
+
        cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
        cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
-       
+
        cam->params.format.subSample = SUBSAMPLE_422;
        cam->params.format.yuvOrder = YUVORDER_YUYV;
-       
+
        cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
        cam->params.compressionTarget.frTargeting =
                CPIA_COMPRESSION_TARGET_QUALITY;
@@ -3898,7 +3898,7 @@ static void reset_camera_struct(struct cam_data *cam)
        cam->params.qx3.cradled = 0;
 
        cam->video_size = VIDEOSIZE_CIF;
-       
+
        cam->vp.colour = 32768;      /* 50% */
        cam->vp.hue = 32768;         /* 50% */
        cam->vp.brightness = 32768;  /* 50% */
@@ -3911,7 +3911,7 @@ static void reset_camera_struct(struct cam_data *cam)
        cam->vc.y = 0;
        cam->vc.width = 0;
        cam->vc.height = 0;
-       
+
        cam->vw.x = 0;
        cam->vw.y = 0;
        set_vw_size(cam);
@@ -3928,7 +3928,7 @@ static void reset_camera_struct(struct cam_data *cam)
 
 /* initialize cam_data structure  */
 static void init_camera_struct(struct cam_data *cam,
-                               struct cpia_camera_ops *ops )
+                              struct cpia_camera_ops *ops )
 {
        int i;
 
@@ -3945,7 +3945,7 @@ static void init_camera_struct(struct cam_data *cam,
 
        memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
        cam->vdev.priv = cam;
-       
+
        cam->curframe = 0;
        for (i = 0; i < FRAME_NUM; i++) {
                cam->frame[i].width = 0;
@@ -3961,15 +3961,15 @@ static void init_camera_struct(struct cam_data *cam,
 
 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
 {
-        struct cam_data *camera;
-       
+       struct cam_data *camera;
+
        if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
                return NULL;
 
-       
+
        init_camera_struct( camera, ops );
        camera->lowlevel_data = lowlevel;
-       
+
        /* register v4l device */
        if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
                kfree(camera);
@@ -3982,7 +3982,7 @@ struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowleve
        /* open cpia */
        if (camera->ops->open(camera->lowlevel_data))
                return camera;
-       
+
        /* reset the camera */
        if (reset_camera(camera) != 0) {
                camera->ops->close(camera->lowlevel_data);
@@ -4022,11 +4022,11 @@ void cpia_unregister_camera(struct cam_data *cam)
                DBG("camera open -- setting ops to NULL\n");
                cam->ops = NULL;
        }
-       
+
 #ifdef CONFIG_PROC_FS
        DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
        destroy_proc_cpia_cam(cam);
-#endif 
+#endif
        if (!cam->open_count) {
                DBG("freeing camera\n");
                kfree(cam);
index de6678200a57ee13c52f59f1e4ddfd4a38636a20..dde27a6a4a095bbc084cfe1f96d58d58466f12c3 100644 (file)
 struct cpia_camera_ops
 {
        /* open sets privdata to point to structure for this camera.
-         * Returns negative value on error, otherwise 0.
+        * Returns negative value on error, otherwise 0.
         */
        int (*open)(void *privdata);
-       
+
        /* Registers callback function cb to be called with cbdata
         * when an image is ready.  If cb is NULL, only single image grabs
         * should be used.  cb should immediately call streamRead to read
@@ -63,8 +63,8 @@ struct cpia_camera_ops
         * otherwise 0.
         */
        int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
-                               void *cbdata);
-       
+                               void *cbdata);
+
        /* transferCmd sends commands to the camera.  command MUST point to
         * an  8 byte buffer in kernel space. data can be NULL if no extra
         * data is needed.  The size of the data is given by the last 2
@@ -77,30 +77,30 @@ struct cpia_camera_ops
         * Returns negative value on error, otherwise 0.
         */
        int (*streamStart)(void *privdata);
-       
+
        /* streamStop terminates stream capture mode.
         * Returns negative value on error, otherwise 0.
         */
        int (*streamStop)(void *privdata);
-        
+
        /* streamRead reads a frame from the camera.  buffer points to a
-         * buffer large enough to hold a complete frame in kernel space.
-         * noblock indicates if this should be a non blocking read.
+        * buffer large enough to hold a complete frame in kernel space.
+        * noblock indicates if this should be a non blocking read.
         * Returns the number of bytes read, or negative value on error.
-         */
+        */
        int (*streamRead)(void *privdata, u8 *buffer, int noblock);
-       
+
        /* close disables the device until open() is called again.
         * Returns negative value on error, otherwise 0.
         */
        int (*close)(void *privdata);
-       
+
        /* If wait_for_stream_ready is non-zero, wait until the streamState
         * is STREAM_READY before calling streamRead.
         */
        int wait_for_stream_ready;
 
-       /* 
+       /*
         * Used to maintain lowlevel module usage counts
         */
        struct module *owner;
@@ -215,14 +215,14 @@ struct cam_params {
                u8 videoSize;           /* CIF/QCIF */
                u8 subSample;
                u8 yuvOrder;
-       } format;
-        struct {                        /* Intel QX3 specific data */
-                u8 qx3_detected;        /* a QX3 is present */
-                u8 toplight;            /* top light lit , R/W */
-                u8 bottomlight;         /* bottom light lit, R/W */
-                u8 button;              /* snapshot button pressed (R/O) */
-                u8 cradled;             /* microscope is in cradle (R/O) */
-        } qx3;
+       } format;
+       struct {                        /* Intel QX3 specific data */
+               u8 qx3_detected;        /* a QX3 is present */
+               u8 toplight;            /* top light lit , R/W */
+               u8 bottomlight;         /* bottom light lit, R/W */
+               u8 button;              /* snapshot button pressed (R/O) */
+               u8 cradled;             /* microscope is in cradle (R/O) */
+       } qx3;
        struct {
                u8 colStart;            /* skip first 8*colStart pixels */
                u8 colEnd;              /* finish at 8*colEnd pixels */
@@ -247,13 +247,13 @@ enum v4l_camstates {
 struct cam_data {
        struct list_head cam_data_list;
 
-        struct mutex busy_lock;     /* guard against SMP multithreading */
+       struct mutex busy_lock;     /* guard against SMP multithreading */
        struct cpia_camera_ops *ops;    /* lowlevel driver operations */
        void *lowlevel_data;            /* private data for lowlevel driver */
        u8 *raw_image;                  /* buffer for raw image data */
        struct cpia_frame decompressed_frame;
-                                        /* buffer to hold decompressed frame */
-       int image_size;                 /* sizeof last decompressed image */
+                                       /* buffer to hold decompressed frame */
+       int image_size;                 /* sizeof last decompressed image */
        int open_count;                 /* # of process that have camera open */
 
                                /* camera status */
@@ -265,7 +265,7 @@ struct cam_data {
        struct mutex param_lock;        /* params lock for this camera */
        struct cam_params params;       /* camera settings */
        struct proc_dir_entry *proc_entry;      /* /proc/cpia/videoX */
-       
+
                                        /* v4l */
        int video_size;                 /* VIDEO_SIZE_ */
        volatile enum v4l_camstates camstate;   /* v4l layer status */
@@ -277,7 +277,7 @@ struct cam_data {
                                /* mmap interface */
        int curframe;                   /* the current frame to grab into */
        u8 *frame_buf;                  /* frame buffer data */
-        struct cpia_frame frame[FRAME_NUM];
+       struct cpia_frame frame[FRAME_NUM];
                                /* FRAME_NUM-buffering, so we need a array */
 
        int first_frame;
@@ -424,7 +424,7 @@ void cpia_unregister_camera(struct cam_data *cam);
 #define DEB_BYTE(p)\
   DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
       (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
-        (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+       (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
 
 #endif /* __KERNEL__ */
 
index 95d3afa94a3d92f09298078561ca22959575f53f..8394283993f6274c5154c999efc167c397a66e30 100644 (file)
@@ -381,7 +381,7 @@ struct cpia2_fh {
 
 struct camera_data {
        /* locks */
-       struct semaphore busy_lock;     /* guard against SMP multithreading */
+       struct mutex busy_lock; /* guard against SMP multithreading */
        struct v4l2_prio_state prio;
 
        /* camera status */
index 5dfb242d5b8c5ddec41661247f6ade6e28b4f24b..fd771c7a2fe24fa930768c612eee546c13f68072 100644 (file)
@@ -2238,7 +2238,7 @@ struct camera_data *cpia2_init_camera_struct(void)
        memset(cam, 0, sizeof(struct camera_data));
 
        cam->present = 1;
-       init_MUTEX(&cam->busy_lock);
+       mutex_init(&cam->busy_lock);
        init_waitqueue_head(&cam->wq_stream);
 
        return cam;
@@ -2371,12 +2371,12 @@ long cpia2_read(struct camera_data *cam,
        }
 
        /* make this _really_ smp and multithread-safe */
-       if (down_interruptible(&cam->busy_lock))
+       if (mutex_lock_interruptible(&cam->busy_lock))
                return -ERESTARTSYS;
 
        if (!cam->present) {
                LOG("%s: camera removed\n",__FUNCTION__);
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return 0;       /* EOF */
        }
 
@@ -2389,34 +2389,34 @@ long cpia2_read(struct camera_data *cam,
        /* Copy cam->curbuff in case it changes while we're processing */
        frame = cam->curbuff;
        if (noblock && frame->status != FRAME_READY) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EAGAIN;
        }
 
        if(frame->status != FRAME_READY) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                wait_event_interruptible(cam->wq_stream,
                               !cam->present ||
                               (frame = cam->curbuff)->status == FRAME_READY);
                if (signal_pending(current))
                        return -ERESTARTSYS;
                /* make this _really_ smp and multithread-safe */
-               if (down_interruptible(&cam->busy_lock)) {
+               if (mutex_lock_interruptible(&cam->busy_lock)) {
                        return -ERESTARTSYS;
                }
                if(!cam->present) {
-                       up(&cam->busy_lock);
+                       mutex_unlock(&cam->busy_lock);
                        return 0;
                }
        }
 
        /* copy data to user space */
        if (frame->length > count) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EFAULT;
        }
        if (copy_to_user(buf, frame->data, frame->length)) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EFAULT;
        }
 
@@ -2424,7 +2424,7 @@ long cpia2_read(struct camera_data *cam,
 
        frame->status = FRAME_EMPTY;
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return count;
 }
 
@@ -2443,10 +2443,10 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
                return POLLERR;
        }
 
-       down(&cam->busy_lock);
+       mutex_lock(&cam->busy_lock);
 
        if(!cam->present) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return POLLHUP;
        }
 
@@ -2456,16 +2456,16 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
                                       cam->params.camera_state.stream_mode);
        }
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        poll_wait(filp, &cam->wq_stream, wait);
-       down(&cam->busy_lock);
+       mutex_lock(&cam->busy_lock);
 
        if(!cam->present)
                status = POLLHUP;
        else if(cam->curbuff->status == FRAME_READY)
                status = POLLIN | POLLRDNORM;
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return status;
 }
 
@@ -2488,18 +2488,18 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
        DBG("mmap offset:%ld size:%ld\n", start_offset, size);
 
        /* make this _really_ smp-safe */
-       if (down_interruptible(&cam->busy_lock))
+       if (mutex_lock_interruptible(&cam->busy_lock))
                return -ERESTARTSYS;
 
        if (!cam->present) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -ENODEV;
        }
 
        if (size > cam->frame_size*cam->num_frames  ||
            (start_offset % cam->frame_size) != 0 ||
            (start_offset+size > cam->frame_size*cam->num_frames)) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EINVAL;
        }
 
@@ -2507,7 +2507,7 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
        while (size > 0) {
                page = kvirt_to_pa(pos);
                if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
-                       up(&cam->busy_lock);
+                       mutex_unlock(&cam->busy_lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -2519,7 +2519,7 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
        }
 
        cam->mmapped = true;
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return 0;
 }
 
index 08f8be345fa80fa80f547bcdc68c9baeb4507c89..481e178ef56df58b197463a0ba250d94811b79d3 100644 (file)
@@ -255,7 +255,7 @@ static int cpia2_open(struct inode *inode, struct file *file)
                return -ENODEV;
        }
 
-       if(down_interruptible(&cam->busy_lock))
+       if(mutex_lock_interruptible(&cam->busy_lock))
                return -ERESTARTSYS;
 
        if(!cam->present) {
@@ -299,7 +299,7 @@ skip_init:
        cpia2_dbg_dump_registers(cam);
 
 err_return:
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return retval;
 }
 
@@ -314,7 +314,7 @@ static int cpia2_close(struct inode *inode, struct file *file)
        struct camera_data *cam = video_get_drvdata(dev);
        struct cpia2_fh *fh = file->private_data;
 
-       down(&cam->busy_lock);
+       mutex_lock(&cam->busy_lock);
 
        if (cam->present &&
            (cam->open_count == 1
@@ -347,7 +347,7 @@ static int cpia2_close(struct inode *inode, struct file *file)
                }
        }
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
 
        return 0;
 }
@@ -523,11 +523,11 @@ static int sync(struct camera_data *cam, int frame_nr)
                        return 0;
                }
 
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                wait_event_interruptible(cam->wq_stream,
                                         !cam->streaming ||
                                         frame->status == FRAME_READY);
-               down(&cam->busy_lock);
+               mutex_lock(&cam->busy_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
                if(!cam->present)
@@ -1544,11 +1544,11 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
        if(frame < 0) {
                /* Wait for a frame to become available */
                struct framebuf *cb=cam->curbuff;
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                wait_event_interruptible(cam->wq_stream,
                                         !cam->present ||
                                         (cb=cam->curbuff)->status == FRAME_READY);
-               down(&cam->busy_lock);
+               mutex_lock(&cam->busy_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
                if(!cam->present)
@@ -1591,11 +1591,11 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
                return -ENOTTY;
 
        /* make this _really_ smp-safe */
-       if (down_interruptible(&cam->busy_lock))
+       if (mutex_lock_interruptible(&cam->busy_lock))
                return -ERESTARTSYS;
 
        if (!cam->present) {
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -ENODEV;
        }
 
@@ -1608,7 +1608,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
                struct cpia2_fh *fh = file->private_data;
                retval = v4l2_prio_check(&cam->prio, &fh->prio);
                if(retval) {
-                       up(&cam->busy_lock);
+                       mutex_unlock(&cam->busy_lock);
                        return retval;
                }
                break;
@@ -1618,7 +1618,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
        {
                struct cpia2_fh *fh = file->private_data;
                if(fh->prio != V4L2_PRIORITY_RECORD) {
-                       up(&cam->busy_lock);
+                       mutex_unlock(&cam->busy_lock);
                        return -EBUSY;
                }
                break;
@@ -1847,7 +1847,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return retval;
 }
 
@@ -1924,14 +1924,15 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
  * The v4l video device structure initialized for this device
  ***/
 static struct file_operations fops_template = {
-       .owner=      THIS_MODULE,
-       .open=       cpia2_open,
-       .release=    cpia2_close,
-       .read=       cpia2_v4l_read,
-       .poll=       cpia2_v4l_poll,
-       .ioctl=      cpia2_ioctl,
-       .llseek=     no_llseek,
-       .mmap=       cpia2_mmap,
+       .owner          = THIS_MODULE,
+       .open           = cpia2_open,
+       .release        = cpia2_close,
+       .read           = cpia2_v4l_read,
+       .poll           = cpia2_v4l_poll,
+       .ioctl          = cpia2_ioctl,
+       .llseek         = no_llseek,
+       .compat_ioctl   = v4l_compat_ioctl32,
+       .mmap           = cpia2_mmap,
 };
 
 static struct video_device cpia2_template = {
index 74cff626e044375a467000ae57a64846af4d7e58..3021f21aae36c7ee33a9b6cdf644a9181e0a7314 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_  1 */  
+/* #define _CPIA_DEBUG_  1 */
 
 #include <linux/config.h>
 
@@ -45,7 +45,7 @@
 
 static int cpia_pp_open(void *privdata);
 static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
-                                    void *cbdata);
+                                   void *cbdata);
 static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
 static int cpia_pp_streamStart(void *privdata);
 static int cpia_pp_streamStop(void *privdata);
@@ -93,7 +93,7 @@ struct pp_cam_entry {
        int stream_irq;
 };
 
-static struct cpia_camera_ops cpia_pp_ops = 
+static struct cpia_camera_ops cpia_pp_ops =
 {
        cpia_pp_open,
        cpia_pp_registerCallback,
@@ -123,7 +123,7 @@ static void cpia_parport_disable_irq( struct parport *port ) {
 }
 
 /* Special CPiA PPC modes: These are invoked by using the 1284 Extensibility
- * Link Flag during negotiation */  
+ * Link Flag during negotiation */
 #define UPLOAD_FLAG  0x08
 #define NIBBLE_TRANSFER 0x01
 #define ECP_TRANSFER 0x03
@@ -139,17 +139,17 @@ static void cpia_parport_disable_irq( struct parport *port ) {
 /*  CPiA nonstandard "Nibble" mode (no nDataAvail signal after each byte). */
 /* The standard kernel parport_ieee1284_read_nibble() fails with the CPiA... */
 
-static size_t cpia_read_nibble (struct parport *port, 
-                        void *buffer, size_t len, 
+static size_t cpia_read_nibble (struct parport *port,
+                        void *buffer, size_t len,
                         int flags)
 {
-       /* adapted verbatim, with one change, from 
+       /* adapted verbatim, with one change, from
           parport_ieee1284_read_nibble() in drivers/parport/ieee1284-ops.c */
 
        unsigned char *buf = buffer;
        int i;
        unsigned char byte = 0;
-       
+
        len *= 2; /* in nibbles */
        for (i=0; i < len; i++) {
                unsigned char nibble;
@@ -158,12 +158,12 @@ static size_t cpia_read_nibble (struct parport *port,
                 * after every second nibble to signal that more
                 * data is available.  (the total number of Bytes that
                 * should be sent is known; if too few are received, an error
-                * will be recorded after a timeout).  
+                * will be recorded after a timeout).
                 * This is incompatible with parport_ieee1284_read_nibble(),
                 * which expects to find nFault LO after every second nibble.
                 */
 
-               /* Solution: modify cpia_read_nibble to only check for 
+               /* Solution: modify cpia_read_nibble to only check for
                 * nDataAvail before the first nibble is sent.
                 */
 
@@ -216,7 +216,7 @@ static size_t cpia_read_nibble (struct parport *port,
                        /* Second nibble */
                        byte |= nibble << 4;
                        *buf++ = byte;
-               } else 
+               } else
                        byte = nibble;
        }
 
@@ -238,18 +238,18 @@ static size_t cpia_read_nibble (struct parport *port,
 }
 
 /* CPiA nonstandard "Nibble Stream" mode (2 nibbles per cycle, instead of 1)
- * (See CPiA Data sheet p. 31) 
- * 
- * "Nibble Stream" mode used by CPiA for uploads to non-ECP ports is a 
- * nonstandard variant of nibble mode which allows the same (mediocre) 
- * data flow of 8 bits per cycle as software-enabled ECP by TRISTATE-capable 
+ * (See CPiA Data sheet p. 31)
+ *
+ * "Nibble Stream" mode used by CPiA for uploads to non-ECP ports is a
+ * nonstandard variant of nibble mode which allows the same (mediocre)
+ * data flow of 8 bits per cycle as software-enabled ECP by TRISTATE-capable
  * parallel ports, but works also for  non-TRISTATE-capable ports.
  * (Standard nibble mode only send 4 bits per cycle)
  *
  */
 
-static size_t cpia_read_nibble_stream(struct parport *port, 
-                              void *buffer, size_t len, 
+static size_t cpia_read_nibble_stream(struct parport *port,
+                              void *buffer, size_t len,
                               int flags)
 {
        int i;
@@ -260,7 +260,7 @@ static size_t cpia_read_nibble_stream(struct parport *port,
                unsigned char nibble[2], byte = 0;
                int j;
 
-               /* Image Data is complete when 4 consecutive EOI bytes (0xff) are seen */ 
+               /* Image Data is complete when 4 consecutive EOI bytes (0xff) are seen */
                if (endseen > 3 )
                        break;
 
@@ -268,7 +268,7 @@ static size_t cpia_read_nibble_stream(struct parport *port,
                parport_frob_control (port,
                                      PARPORT_CONTROL_AUTOFD,
                                      PARPORT_CONTROL_AUTOFD);
-               
+
                /* Event 9: nAck goes low. */
                port->ieee1284.phase = IEEE1284_PH_REV_DATA;
                if (parport_wait_peripheral (port,
@@ -282,7 +282,7 @@ static size_t cpia_read_nibble_stream(struct parport *port,
 
                /* Read lower nibble */
                nibble[0] = parport_read_status (port) >>3;
-               
+
                /* Event 10: Set nAutoFd high. */
                parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
 
@@ -295,10 +295,10 @@ static size_t cpia_read_nibble_stream(struct parport *port,
                                 port->name);
                        break;
                }
-               
+
                /* Read upper nibble */
                nibble[1] = parport_read_status (port) >>3;
-               
+
                /* reassemble the byte */
                for (j = 0; j < 2 ; j++ ) {
                        nibble[j] &= ~8;
@@ -335,8 +335,8 @@ static void EndTransferMode(struct pp_cam_entry *cam)
 static int ForwardSetup(struct pp_cam_entry *cam)
 {
        int retry;
-       
-       /* The CPiA uses ECP protocol for Downloads from the Host to the camera. 
+
+       /* The CPiA uses ECP protocol for Downloads from the Host to the camera.
         * This will be software-emulated if ECP hardware is not present
         */
 
@@ -375,9 +375,9 @@ static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
        upload_mode = mode;
        if(extensibility) mode = UPLOAD_FLAG|transfer_mode|IEEE1284_EXT_LINK;
 
-       /* the usual camera maximum response time is 10ms, but after 
+       /* the usual camera maximum response time is 10ms, but after
         * receiving some commands, it needs up to 40ms. */
-               
+
        for(retry = 0; retry < 4; ++retry) {
                if(!parport_negotiate(cam->port, mode)) {
                        break;
@@ -439,10 +439,10 @@ static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
 
        /* support for CPiA variant nibble reads */
        if(cam->port->ieee1284.mode == IEEE1284_MODE_NIBBLE) {
-               if(cpia_read_nibble(cam->port, packet, size, 0) != size) 
-                       retval = -EIO;                  
+               if(cpia_read_nibble(cam->port, packet, size, 0) != size)
+                       retval = -EIO;
        } else {
-               if(parport_read(cam->port, packet, size) != size) 
+               if(parport_read(cam->port, packet, size) != size)
                        retval = -EIO;
        }
        EndTransferMode(cam);
@@ -542,18 +542,18 @@ static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
        block_size = PARPORT_CHUNK_SIZE;
        while( !cam->image_complete ) {
                cond_resched();
-               
+
                new_bytes = cpia_pp_read(cam->port, buffer, block_size );
                if( new_bytes <= 0 ) {
                        break;
                }
                i=-1;
                while(++i<new_bytes && endseen<4) {
-                       if(*buffer==EOI) {
-                               endseen++;
-                       } else {
-                               endseen=0;
-                       }
+                       if(*buffer==EOI) {
+                               endseen++;
+                       } else {
+                               endseen=0;
+                       }
                        buffer++;
                }
                read_bytes += i;
@@ -601,7 +601,7 @@ static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
                }
                if((err = ReadPacket(cam, buffer, 8)) < 0) {
                        DBG("Error reading command result\n");
-                       return err;
+                      return err;
                }
                memcpy(data, buffer, databytes);
        } else if(command[0] == DATA_OUT) {
@@ -631,10 +631,10 @@ static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
 static int cpia_pp_open(void *privdata)
 {
        struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
-       
+
        if (cam == NULL)
                return -EINVAL;
-       
+
        if(cam->open_count == 0) {
                if (parport_claim(cam->pdev)) {
                        DBG("failed to claim the port\n");
@@ -645,12 +645,12 @@ static int cpia_pp_open(void *privdata)
                parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
                udelay(50);
                parport_write_control(cam->port,
-                                     PARPORT_CONTROL_SELECT
-                                     | PARPORT_CONTROL_INIT);
+                                     PARPORT_CONTROL_SELECT
+                                     | PARPORT_CONTROL_INIT);
        }
-       
+
        ++cam->open_count;
-       
+
        return 0;
 }
 
@@ -663,7 +663,7 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo
 {
        struct pp_cam_entry *cam = privdata;
        int retval = 0;
-       
+
        if(cam->port->irq != PARPORT_IRQ_NONE) {
                INIT_WORK(&cam->cb_task, cb, cbdata);
        } else {
@@ -707,9 +707,9 @@ static int cpia_pp_register(struct parport *port)
                LOG("failed to allocate camera structure\n");
                return -ENOMEM;
        }
-       
+
        pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
-                                      NULL, 0, cam);
+                                      NULL, 0, cam);
 
        if (!pdev) {
                LOG("failed to parport_register_device\n");
@@ -753,19 +753,19 @@ static void cpia_pp_detach (struct parport *port)
                }
                cpia = NULL;
        }
-       spin_unlock( &cam_list_lock_pp );                       
+       spin_unlock( &cam_list_lock_pp );
 
        if (!cpia) {
                DBG("cpia_pp_detach failed to find cam_data in cam_list\n");
                return;
        }
-       
-       cam = (struct pp_cam_entry *) cpia->lowlevel_data;      
+
+       cam = (struct pp_cam_entry *) cpia->lowlevel_data;
        cpia_unregister_camera(cpia);
-       if(cam->open_count > 0) 
+       if(cam->open_count > 0)
                cpia_pp_close(cam);
        parport_unregister_device(cam->pdev);
-       cpia->lowlevel_data = NULL;     
+       cpia->lowlevel_data = NULL;
        kfree(cam);
 }
 
@@ -805,14 +805,14 @@ static struct parport_driver cpia_pp_driver = {
 
 int cpia_pp_init(void)
 {
-       printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, 
+       printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
               CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
 
        if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
                printk("  disabled\n");
                return 0;
        }
-       
+
        spin_lock_init( &cam_list_lock_pp );
 
        if (parport_register_driver (&cpia_pp_driver)) {
index 03275c37c5d330b344e5150d4ae7482942e8ee5a..9c49a4b00116f1ef7075888ecd26f6b261bcb75b 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_  1 */  
+/* #define _CPIA_DEBUG_  1 */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -85,7 +85,7 @@ struct usb_cpia {
 
 static int cpia_usb_open(void *privdata);
 static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
-                                    void *cbdata);
+                                    void *cbdata);
 static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
 static int cpia_usb_streamStart(void *privdata);
 static int cpia_usb_streamStop(void *privdata);
@@ -127,7 +127,7 @@ static void cpia_usb_complete(struct urb *urb, struct pt_regs *regs)
                ucpia->workbuff->status = FRAME_READING;
                ucpia->workbuff->length = 0;
        }
-                 
+
        for (i = 0; i < urb->number_of_packets; i++) {
                int n = urb->iso_frame_desc[i].actual_length;
                int st = urb->iso_frame_desc[i].status;
@@ -141,9 +141,9 @@ static void cpia_usb_complete(struct urb *urb, struct pt_regs *regs)
                        printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
                        return;
                }
-           
+
                if (n) {
-                       if ((ucpia->workbuff->length > 0) || 
+                       if ((ucpia->workbuff->length > 0) ||
                            (0x19 == cdata[0] && 0x68 == cdata[1])) {
                                memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
                                ucpia->workbuff->length += n;
@@ -160,7 +160,7 @@ static void cpia_usb_complete(struct urb *urb, struct pt_regs *regs)
                                ucpia->workbuff = ucpia->workbuff->next;
                                ucpia->workbuff->status = FRAME_EMPTY;
                                ucpia->workbuff->length = 0;
-                 
+
                                if (waitqueue_active(&ucpia->wq_stream))
                                        wake_up_interruptible(&ucpia->wq_stream);
                        }
@@ -178,7 +178,7 @@ static int cpia_usb_open(void *privdata)
        struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
        struct urb *urb;
        int ret, retval = 0, fx, err;
-  
+
        if (!ucpia)
                return -EINVAL;
 
@@ -191,7 +191,7 @@ static int cpia_usb_open(void *privdata)
                retval = -EINVAL;
                goto error_0;
        }
-       
+
        ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
        if (ret < 0) {
                printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
@@ -286,7 +286,7 @@ error_1:
 error_0:
        kfree (ucpia->sbuf[0].data);
        ucpia->sbuf[0].data = NULL;
-       
+
        return retval;
 }
 
@@ -307,7 +307,7 @@ static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_
        return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                         packet[1] + (packet[0] << 8),
                         USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                        packet[2] + (packet[3] << 8), 
+                        packet[2] + (packet[3] << 8),
                         packet[4] + (packet[5] << 8), buf, size, 1000);
 }
 
@@ -324,7 +324,7 @@ static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
        return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                         packet[1] + (packet[0] << 8),
                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                        packet[2] + (packet[3] << 8), 
+                        packet[2] + (packet[3] << 8),
                         packet[4] + (packet[5] << 8), buf, size, 1000);
 }
 
@@ -393,7 +393,7 @@ static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
 
        if (!ucpia || !ucpia->present)
                return -1;
-  
+
        if (ucpia->curbuff->status != FRAME_READY)
                interruptible_sleep_on(&ucpia->wq_stream);
        else
@@ -403,7 +403,7 @@ static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
 
        if (!mybuff)
                return -1;
-  
+
        if (mybuff->status != FRAME_READY || mybuff->length < 4) {
                DBG("Something went wrong!\n");
                return -1;
@@ -411,7 +411,7 @@ static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
 
        memcpy(frame, mybuff->data, mybuff->length);
        mybuff->status = FRAME_EMPTY;
-  
+
 /*   DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n",  */
 /*       mybuff->length, frame[0], frame[1], */
 /*       frame[mybuff->length-4], frame[mybuff->length-3],  */
@@ -447,7 +447,7 @@ static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
 
        kfree(ucpia->sbuf[1].data);
        ucpia->sbuf[1].data = NULL;
+
        if (ucpia->sbuf[0].urb) {
                usb_kill_urb(ucpia->sbuf[0].urb);
                usb_free_urb(ucpia->sbuf[0].urb);
@@ -490,7 +490,7 @@ static int cpia_probe(struct usb_interface *intf,
        struct usb_cpia *ucpia;
        struct cam_data *cam;
        int ret;
-  
+
        /* A multi-config CPiA camera? */
        if (udev->descriptor.bNumConfigurations != 1)
                return -ENODEV;
@@ -539,7 +539,7 @@ static int cpia_probe(struct usb_interface *intf,
 
        /* Before register_camera, important */
        ucpia->present = 1;
-  
+
        cam = cpia_register_camera(&cpia_usb_ops, ucpia);
        if (!cam) {
                LOG("failed to cpia_register_camera\n");
@@ -591,7 +591,7 @@ static void cpia_disconnect(struct usb_interface *intf)
        struct cam_data *cam = usb_get_intfdata(intf);
        struct usb_cpia *ucpia;
        struct usb_device *udev;
-  
+
        usb_set_intfdata(intf, NULL);
        if (!cam)
                return;
@@ -600,7 +600,7 @@ static void cpia_disconnect(struct usb_interface *intf)
        spin_lock( &cam_list_lock_usb );
        list_del(&cam->cam_data_list);
        spin_unlock( &cam_list_lock_usb );
-       
+
        ucpia->present = 0;
 
        cpia_unregister_camera(cam);
@@ -631,7 +631,7 @@ static void cpia_disconnect(struct usb_interface *intf)
 
 static int __init usb_cpia_init(void)
 {
-       printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, 
+       printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
               CPIA_USB_MAJ_VER,CPIA_USB_MIN_VER,CPIA_USB_PATCH_VER);
 
        spin_lock_init(&cam_list_lock_usb);
index 8739c64785ef4a2c73092c9b4c12d64d3fc84305..de87247c74ee95138b78fa9f7d1eabd62700b8d3 100644 (file)
@@ -59,25 +59,25 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
 static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
                            void *arg)
 {
-       struct v4l2_audio *input = arg;
+       struct v4l2_routing *route = arg;
        struct v4l2_control *ctrl = arg;
 
        switch (cmd) {
-       case VIDIOC_S_AUDIO:
+       case VIDIOC_INT_G_AUDIO_ROUTING:
+               route->input = (cs53l32a_read(client, 0x01) >> 4) & 3;
+               route->output = 0;
+               break;
+
+       case VIDIOC_INT_S_AUDIO_ROUTING:
                /* There are 2 physical inputs, but the second input can be
                   placed in two modes, the first mode bypasses the PGA (gain),
                   the second goes through the PGA. Hence there are three
                   possible inputs to choose from. */
-               if (input->index > 2) {
-                       v4l_err(client, "Invalid input %d.\n", input->index);
+               if (route->input > 2) {
+                       v4l_err(client, "Invalid input %d.\n", route->input);
                        return -EINVAL;
                }
-               cs53l32a_write(client, 0x01, 0x01 + (input->index << 4));
-               break;
-
-       case VIDIOC_G_AUDIO:
-               memset(input, 0, sizeof(*input));
-               input->index = (cs53l32a_read(client, 0x01) >> 4) & 3;
+               cs53l32a_write(client, 0x01, 0x01 + (route->input << 4));
                break;
 
        case VIDIOC_G_CTRL:
index 2b22f3a38de5ea738397bbe55973e85819fa06be..621c0c6678ea6bf9863031b3ea24b6c53b3cc4a6 100644 (file)
@@ -20,7 +20,7 @@
 #define __CS8420_H__
 
 /* Initialization Sequence */
-        
+
 static __u8 init8420[] = {
        1, 0x01,        2, 0x02,        3, 0x00,        4, 0x46,
        5, 0x24,        6, 0x84,        18, 0x18,       19, 0x13,
index cb9a7981e4081bc9ac284b2ff26c47b6f84fdd23..a4540e858f213883fa5cfe8d40b3fdbc46e4611b 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
-#include <media/audiochip.h>
 #include <media/v4l2-common.h>
 
 #include "cx25840.h"
index 8a257978056ffcb520202c6abe4094c6f33d0357..a65b3cc4bf03ff00bd2cf991ccc88abc632adc88 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
-#include <media/audiochip.h>
 #include <media/v4l2-common.h>
 
 #include "cx25840.h"
@@ -176,9 +175,9 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
        cx25840_write(client, 0x4a5, 0x00);
        cx25840_write(client, 0x402, 0x00);
        /* 8. */
-       cx25840_write(client, 0x401, 0x18);
-       cx25840_write(client, 0x4a2, 0x10);
-       cx25840_write(client, 0x402, 0x04);
+       cx25840_and_or(client, 0x401, ~0x18, 0);
+       cx25840_and_or(client, 0x4a2, ~0x10, 0x10);
+       /* steps 8c and 8d are done in change_input() */
        /* 10. */
        cx25840_write(client, 0x8d3, 0x1f);
        cx25840_write(client, 0x8e3, 0x03);
@@ -209,6 +208,17 @@ static void input_change(struct i2c_client *client)
        struct cx25840_state *state = i2c_get_clientdata(client);
        v4l2_std_id std = cx25840_get_v4lstd(client);
 
+       /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
+       if (std & V4L2_STD_SECAM) {
+               cx25840_write(client, 0x402, 0);
+       }
+       else {
+               cx25840_write(client, 0x402, 0x04);
+               cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+       }
+       cx25840_and_or(client, 0x401, ~0x60, 0);
+       cx25840_and_or(client, 0x401, ~0x60, 0x60);
+
        /* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC
           instead of V4L2_STD_PAL. Someone needs to test this. */
        if (std & V4L2_STD_PAL) {
@@ -343,6 +353,15 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
                }
        }
 
+       /* Follow step 9 of section 3.16 in the cx25840 datasheet.
+          Without this PAL may display a vertical ghosting effect.
+          This happens for example with the Yuan MPC622. */
+       if (fmt >= 4 && fmt < 8) {
+               /* Set format to NTSC-M */
+               cx25840_and_or(client, 0x400, ~0xf, 1);
+               /* Turn off LCOMB */
+               cx25840_and_or(client, 0x47b, ~6, 0);
+       }
        cx25840_and_or(client, 0x400, ~0xf, fmt);
        cx25840_vbi_setup(client);
        return 0;
@@ -359,7 +378,14 @@ v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
        }
 
        switch (fmt) {
-       case 0x1: return V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR;
+       case 0x1:
+       {
+               /* if the audio std is A2-M, then this is the South Korean
+                  NTSC standard */
+               if (cx25840_read(client, 0x805) == 2)
+                       return V4L2_STD_NTSC_M_KR;
+               return V4L2_STD_NTSC_M;
+       }
        case 0x2: return V4L2_STD_NTSC_M_JP;
        case 0x3: return V4L2_STD_NTSC_443;
        case 0x4: return V4L2_STD_PAL;
@@ -737,16 +763,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                return set_input(client, state->vid_input, input->index);
        }
 
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *input = arg;
-
-               memset(input, 0, sizeof(*input));
-               input->index = state->aud_input;
-               input->capability = V4L2_AUDCAP_STEREO;
-               break;
-       }
-
        case VIDIOC_S_FREQUENCY:
                input_change(client);
                break;
@@ -794,13 +810,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                           bilingual -> lang1 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x00);
                        break;
+               case V4L2_TUNER_MODE_STEREO:
                case V4L2_TUNER_MODE_LANG1:
                        /* mono      -> mono
                           stereo    -> stereo
                           bilingual -> lang1 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x04);
                        break;
-               case V4L2_TUNER_MODE_STEREO:
+               case V4L2_TUNER_MODE_LANG1_LANG2:
                        /* mono      -> mono
                           stereo    -> stereo
                           bilingual -> lang1/lang2 */
@@ -808,7 +825,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        break;
                case V4L2_TUNER_MODE_LANG2:
                        /* mono      -> mono
-                          stereo    ->stereo
+                          stereo    -> stereo
                           bilingual -> lang2 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x01);
                        break;
index e140996e6ee4d43eecb7df09ded07cf680887d6d..ff0f72340d6911802b4a7f9a4a440105e89d2bc6 100644 (file)
@@ -16,12 +16,13 @@ config VIDEO_CX88
          module will be called cx8800
 
 config VIDEO_CX88_ALSA
-       tristate "ALSA DMA audio support"
+       tristate "Conexant 2388x DMA audio support"
        depends on VIDEO_CX88 && SND && EXPERIMENTAL
        select SND_PCM
        ---help---
          This is a video4linux driver for direct (DMA) audio on
-         Conexant 2388x based TV cards.
+         Conexant 2388x based TV cards using ALSA.
+
          It only works with boards with function 01 enabled.
          To check if your board supports, use lspci -n.
          If supported, you should see 1471:8801 or 1471:8811
index 3170b8f72c68e139de625d6f8838ea6ed8415e82..f9d87b86492c7e374a14dcff6292e41bd2ae1f9c 100644 (file)
@@ -303,7 +303,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
        BUG_ON(!chip->dma_size);
 
        dprintk(2,"Freeing buffer\n");
-       videobuf_dma_pci_unmap(chip->pci, &chip->dma_risc);
+       videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc);
        videobuf_dma_free(&chip->dma_risc);
        btcx_riscmem_free(chip->pci,&chip->buf->risc);
        kfree(chip->buf);
@@ -429,7 +429,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
        videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
                        (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
 
-       videobuf_dma_pci_map(chip->pci,&buf->vb.dma);
+       videobuf_pci_dma_map(chip->pci,&buf->vb.dma);
 
 
        cx88_risc_databuffer(chip->pci, &buf->risc,
index a502a4d6e4ae0ea68e01e9ed7875217d2d514865..e100d8ef369a250155cde5378c999a98201ba39b 100644 (file)
@@ -1341,7 +1341,7 @@ bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
               enum v4l2_field field)
 {
        struct cx8802_fh *fh = q->priv_data;
-       return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb, field);
+       return cx8802_buf_prepare(q, fh->dev, (struct cx88_buffer*)vb, field);
 }
 
 static void
@@ -1354,8 +1354,7 @@ bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 static void
 bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct cx8802_fh *fh = q->priv_data;
-       cx88_free_buffer(fh->dev->pci, (struct cx88_buffer*)vb);
+       cx88_free_buffer(q, (struct cx88_buffer*)vb);
 }
 
 static struct videobuf_queue_ops blackbird_qops = {
index c2cdbafdb77b34ae3b06b723f5e963e61854f92b..2c3d9f1999be6e5884e912bad2476f8b99fec16a 100644 (file)
@@ -213,13 +213,13 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 void
-cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
+cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
 {
        BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_pci_unmap(pci, &buf->vb.dma);
+       videobuf_dma_unmap(q, &buf->vb.dma);
        videobuf_dma_free(&buf->vb.dma);
-       btcx_riscmem_free(pci, &buf->risc);
+       btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
        buf->vb.state = STATE_NEEDS_INIT;
 }
 
index a9fc2695b157449c18670f0a37d4bca257098596..f0ea9b5cdbc234c50bcd8bb9f93aaa7c3b42f904 100644 (file)
@@ -90,7 +90,7 @@ static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                           enum v4l2_field field)
 {
        struct cx8802_dev *dev = q->priv_data;
-       return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb,field);
+       return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
 }
 
 static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -101,8 +101,7 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 
 static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct cx8802_dev *dev = q->priv_data;
-       cx88_free_buffer(dev->pci, (struct cx88_buffer*)vb);
+       cx88_free_buffer(q, (struct cx88_buffer*)vb);
 }
 
 static struct videobuf_queue_ops dvb_qops = {
index c79cc1d2bf8b1f95c27d7151189b52195ab9b401..7d16888b4a866d2d250a1dce4c81b7b6c63a1426 100644 (file)
@@ -163,8 +163,8 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
 
 /* ------------------------------------------------------------------ */
 
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
-                       enum v4l2_field field)
+int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
+                       struct cx88_buffer *buf, enum v4l2_field field)
 {
        int size = dev->ts_packet_size * dev->ts_packet_count;
        int rc;
@@ -179,7 +179,7 @@ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
                buf->vb.size   = size;
                buf->vb.field  = field /*V4L2_FIELD_TOP*/;
 
-               if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+               if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
                        goto fail;
                cx88_risc_databuffer(dev->pci, &buf->risc,
                                     buf->vb.dma.sglist,
@@ -189,36 +189,36 @@ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
        return 0;
 
  fail:
-       cx88_free_buffer(dev->pci,buf);
+       cx88_free_buffer(q,buf);
        return rc;
 }
 
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
 {
        struct cx88_buffer    *prev;
-       struct cx88_dmaqueue  *q    = &dev->mpegq;
+       struct cx88_dmaqueue  *cx88q = &dev->mpegq;
 
        dprintk( 1, "cx8802_buf_queue\n" );
        /* add jump to stopper */
        buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-       buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+       buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
 
-       if (list_empty(&q->active)) {
+       if (list_empty(&cx88q->active)) {
                dprintk( 0, "queue is empty - first active\n" );
-               list_add_tail(&buf->vb.queue,&q->active);
-               cx8802_start_dma(dev, q, buf);
+               list_add_tail(&buf->vb.queue,&cx88q->active);
+               cx8802_start_dma(dev, cx88q, buf);
                buf->vb.state = STATE_ACTIVE;
-               buf->count    = q->count++;
-               mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+               buf->count    = cx88q->count++;
+               mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
                dprintk(0,"[%p/%d] %s - first active\n",
                        buf, buf->vb.i, __FUNCTION__);
 
        } else {
                dprintk( 1, "queue is not empty - append to active\n" );
-               prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
-               list_add_tail(&buf->vb.queue,&q->active);
+               prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
+               list_add_tail(&buf->vb.queue,&cx88q->active);
                buf->vb.state = STATE_ACTIVE;
-               buf->count    = q->count++;
+               buf->count    = cx88q->count++;
                prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
                dprintk( 1, "[%p/%d] %s - append to active\n",
                        buf, buf->vb.i, __FUNCTION__);
index da8d97ce0c4b559e22e4705b20613baa7b1bd77c..641a0c5a64907422777039dfd9f34f0d4f321828 100644 (file)
@@ -885,6 +885,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                        set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP);
                        break;
                case V4L2_TUNER_MODE_STEREO:
+               case V4L2_TUNER_MODE_LANG1_LANG2:
                        set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO);
                        break;
                }
@@ -905,6 +906,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                                                         EN_NICAM_FORCE_MONO2);
                                break;
                        case V4L2_TUNER_MODE_STEREO:
+                       case V4L2_TUNER_MODE_LANG1_LANG2:
                                set_audio_standard_NICAM(core,
                                                         EN_NICAM_FORCE_STEREO);
                                break;
@@ -926,6 +928,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                                                              EN_A2_FORCE_MONO2);
                                        break;
                                case V4L2_TUNER_MODE_STEREO:
+                               case V4L2_TUNER_MODE_LANG1_LANG2:
                                        set_audio_standard_A2(core,
                                                              EN_A2_FORCE_STEREO);
                                        break;
index 9bc6c89955816fa3d58f122c5382c06e2c0e5757..846faadc9f1c22c20e1373cfa9d35b11a516c54f 100644 (file)
@@ -175,7 +175,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                buf->vb.size   = size;
                buf->vb.field  = V4L2_FIELD_SEQ_TB;
 
-               if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+               if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
                        goto fail;
                cx88_risc_buffer(dev->pci, &buf->risc,
                                 buf->vb.dma.sglist,
@@ -187,7 +187,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        return 0;
 
  fail:
-       cx88_free_buffer(dev->pci,buf);
+       cx88_free_buffer(q,buf);
        return rc;
 }
 
@@ -227,9 +227,8 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
-       struct cx8800_fh   *fh  = q->priv_data;
 
-       cx88_free_buffer(fh->dev->pci,buf);
+       cx88_free_buffer(q,buf);
 }
 
 struct videobuf_queue_ops cx8800_vbi_qops = {
index 6c97aa740d27f776f381aa7e2b5b2864325c8160..72a417b3174521e2f67aac7944274351052307e8 100644 (file)
@@ -564,7 +564,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
                init_buffer = 1;
-               if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+               if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
                        goto fail;
        }
 
@@ -614,7 +614,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        return 0;
 
  fail:
-       cx88_free_buffer(dev->pci,buf);
+       cx88_free_buffer(q,buf);
        return rc;
 }
 
@@ -671,9 +671,8 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
-       struct cx8800_fh   *fh  = q->priv_data;
 
-       cx88_free_buffer(fh->dev->pci,buf);
+       cx88_free_buffer(q,buf);
 }
 
 static struct videobuf_queue_ops cx8800_video_qops = {
@@ -1251,9 +1250,17 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 {
        int err;
 
-       dprintk(2, "CORE IOCTL: 0x%x\n", cmd );
-       if (video_debug > 1)
-               v4l_print_ioctl(core->name,cmd);
+       if (video_debug) {
+              if (video_debug > 1) {
+                      if (_IOC_DIR(cmd) & _IOC_WRITE)
+                              v4l_printk_ioctl_arg("cx88(w)",cmd, arg);
+                      else if (!_IOC_DIR(cmd) & _IOC_READ) {
+                              v4l_print_ioctl("cx88", cmd);
+                      }
+              } else
+                      v4l_print_ioctl(core->name,cmd);
+
+       }
 
        switch (cmd) {
        /* ---------- tv norms ---------- */
@@ -1460,7 +1467,19 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 static int video_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+       int retval;
+
+       retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+
+       if (video_debug > 1) {
+              if (retval < 0) {
+                      v4l_print_ioctl("cx88(err)", cmd);
+                      printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval);
+              } else if (_IOC_DIR(cmd) & _IOC_READ)
+                      v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg);
+       }
+
+       return retval;
 }
 
 /* ----------------------------------------------------------- */
index cfa8668784b42f7aa754105adee998e4b68b47a5..326a25f147f67c4e96ee16cd81d92b107829c0cd 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <media/tuner.h>
 #include <media/tveeprom.h>
-#include <media/audiochip.h>
 #include <media/video-buf.h>
 #include <media/video-buf-dvb.h>
 
@@ -485,7 +484,7 @@ extern int
 cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
                  u32 reg, u32 mask, u32 value);
 extern void
-cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf);
+cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
 
 extern void cx88_risc_disasm(struct cx88_core *core,
                             struct btcx_riscmem *risc);
@@ -577,8 +576,8 @@ void cx88_ir_irq(struct cx88_core *core);
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
 
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
-                       enum v4l2_field field);
+int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
+                       struct cx88_buffer *buf, enum v4l2_field field);
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
 void cx8802_cancel_buffers(struct cx8802_dev *dev);
 
diff --git a/drivers/media/video/dabfirmware.h b/drivers/media/video/dabfirmware.h
new file mode 100644 (file)
index 0000000..d14d803
--- /dev/null
@@ -0,0 +1,1408 @@
+/*
+ * dabdata.h - dab usb firmware and bitstream data
+ */
+
+static INTEL_HEX_RECORD firmware[] = {
+
+{  2, 0x0000, 0, {0x21,0x57} },
+{  3, 0x0003, 0, {0x02,0x01,0x66} },
+{  3, 0x000b, 0, {0x02,0x01,0x66} },
+{  3, 0x0013, 0, {0x02,0x01,0x66} },
+{  3, 0x001b, 0, {0x02,0x01,0x66} },
+{  3, 0x0023, 0, {0x02,0x01,0x66} },
+{  3, 0x002b, 0, {0x02,0x01,0x66} },
+{  3, 0x0033, 0, {0x02,0x03,0x0f} },
+{  3, 0x003b, 0, {0x02,0x01,0x66} },
+{  3, 0x0043, 0, {0x02,0x01,0x00} },
+{  3, 0x004b, 0, {0x02,0x01,0x66} },
+{  3, 0x0053, 0, {0x02,0x01,0x66} },
+{  3, 0x005b, 0, {0x02,0x04,0xbd} },
+{  3, 0x0063, 0, {0x02,0x01,0x67} },
+{  3, 0x0100, 0, {0x02,0x0c,0x5a} },
+{  3, 0x0104, 0, {0x02,0x01,0xed} },
+{  3, 0x0108, 0, {0x02,0x02,0x51} },
+{  3, 0x010c, 0, {0x02,0x02,0x7c} },
+{  3, 0x0110, 0, {0x02,0x02,0xe4} },
+{  1, 0x0114, 0, {0x32} },
+{  1, 0x0118, 0, {0x32} },
+{  3, 0x011c, 0, {0x02,0x05,0xfd} },
+{  3, 0x0120, 0, {0x02,0x00,0x00} },
+{  3, 0x0124, 0, {0x02,0x00,0x00} },
+{  3, 0x0128, 0, {0x02,0x04,0x3c} },
+{  3, 0x012c, 0, {0x02,0x04,0x6a} },
+{  3, 0x0130, 0, {0x02,0x00,0x00} },
+{  3, 0x0134, 0, {0x02,0x00,0x00} },
+{  3, 0x0138, 0, {0x02,0x00,0x00} },
+{  3, 0x013c, 0, {0x02,0x00,0x00} },
+{  3, 0x0140, 0, {0x02,0x00,0x00} },
+{  3, 0x0144, 0, {0x02,0x00,0x00} },
+{  3, 0x0148, 0, {0x02,0x00,0x00} },
+{  3, 0x014c, 0, {0x02,0x00,0x00} },
+{  3, 0x0150, 0, {0x02,0x00,0x00} },
+{  3, 0x0154, 0, {0x02,0x00,0x00} },
+{ 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} },
+{  5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} },
+{  1, 0x0166, 0, {0x32} },
+{ 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} },
+{ 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} },
+{  3, 0x019f, 0, {0x55,0x7f,0xf0} },
+{ 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} },
+{  3, 0x01da, 0, {0xd0,0xd0,0x32} },
+{  8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} },
+{  7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} },
+{  1, 0x01ec, 0, {0x22} },
+{ 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} },
+{ 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} },
+{ 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} },
+{  9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} },
+{  4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} },
+{ 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} },
+{ 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} },
+{  2, 0x023c, 0, {0x01,0x0b} },
+{  2, 0x023e, 0, {0x80,0xe3} },
+{  2, 0x0240, 0, {0xd0,0x86} },
+{ 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} },
+{  1, 0x0250, 0, {0x32} },
+{ 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
+{  4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} },
+{ 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} },
+{  6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} },
+{  6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
+{ 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} },
+{ 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
+{  4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} },
+{ 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} },
+{  7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} },
+{  6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
+{ 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} },
+{  5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} },
+{ 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
+{ 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} },
+{ 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} },
+{  1, 0x0398, 0, {0xf0} },
+{  1, 0x0399, 0, {0x22} },
+{ 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
+{ 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} },
+{ 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} },
+{ 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} },
+{  1, 0x03ca, 0, {0x22} },
+{ 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} },
+{  9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} },
+{  2, 0x03de, 0, {0x03,0x72} },
+{  1, 0x03e0, 0, {0x22} },
+{ 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} },
+{  9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} },
+{  9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} },
+{  9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} },
+{  8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} },
+{  1, 0x0410, 0,{0x22} },
+{ 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
+{  4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} },
+{ 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} },
+{  7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} },
+{ 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
+{  7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} },
+{ 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} },
+{ 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} },
+{ 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} },
+{  1, 0x04ee, 0, {0x22} },
+{  7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} },
+{  1, 0x04f6, 0, {0x22} },
+{ 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} },
+{ 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} },
+{ 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} },
+{ 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} },
+{  2, 0x052c, 0, {0x7a,0x00} },
+{  7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} },
+{  2, 0x0535, 0, {0x7b,0x00} },
+{ 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} },
+{  7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} },
+{  9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} },
+{  4, 0x0552, 0, {0x70,0x47,0x75,0x71} },
+{  8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} },
+{  5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} },
+{  1, 0x0563, 0, {0x22} },
+{ 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
+{ 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} },
+{ 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} },
+{ 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} },
+{  5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} },
+{  3, 0x05a1, 0, {0x02,0x05,0xf9} },
+{  6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} },
+{ 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} },
+{ 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} },
+{  2, 0x05c6, 0, {0x80,0x31} },
+{ 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} },
+{ 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} },
+{ 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} },
+{  7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} },
+{  3, 0x05f9, 0, {0x75,0x38,0x01} },
+{  1, 0x05fc, 0, {0x22} },
+{ 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} },
+{ 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} },
+{ 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} },
+{ 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} },
+{ 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} },
+{ 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} },
+{ 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} },
+{  3, 0x06a2, 0, {0xbf,0x81,0x0a} },
+{ 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} },
+{  8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} },
+{  3, 0x06b7, 0, {0xba,0x01,0x0c} },
+{ 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
+{ 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} },
+{  8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} },
+{  3, 0x06d9, 0, {0xba,0x01,0x0d} },
+{ 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
+{ 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} },
+{  8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} },
+{  3, 0x06fc, 0, {0xba,0x01,0x0d} },
+{ 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} },
+{ 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} },
+{  5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} },
+{  1, 0x071d, 0, {0x22} },
+{ 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} },
+{ 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} },
+{  3, 0x074d, 0, {0xba,0xff,0x00} },
+{  2, 0x0750, 0, {0x50,0x0a} },
+{ 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
+{ 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} },
+{  8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} },
+{  1, 0x076e, 0, {0x22} },
+{ 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} },
+{ 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} },
+{ 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} },
+{  9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} },
+{  5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} },
+{  7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} },
+{ 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} },
+{  4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} },
+{  9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} },
+{  7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} },
+{ 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} },
+{ 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} },
+{ 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
+{ 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} },
+{ 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} },
+{ 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} },
+{ 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} },
+{ 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} },
+{ 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} },
+{ 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} },
+{ 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} },
+{ 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} },
+{ 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} },
+{  9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} },
+{ 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} },
+{  9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x089d, 0, {0x80,0xe0} },
+{ 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} },
+{ 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} },
+{ 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{ 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x08d0, 0, {0x80,0xd9} },
+{ 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} },
+{ 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} },
+{ 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} },
+{ 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} },
+{ 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} },
+{ 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} },
+{ 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} },
+{ 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} },
+{  3, 0x0937, 0, {0x02,0x0a,0x3f} },
+{ 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} },
+{ 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} },
+{ 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
+{ 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} },
+{ 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} },
+{  2, 0x097a, 0, {0x60,0x0c} },
+{ 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} },
+{ 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} },
+{ 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} },
+{  6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} },
+{  3, 0x09a7, 0, {0xba,0xa0,0x00} },
+{  2, 0x09aa, 0, {0x50,0x24} },
+{ 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} },
+{ 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} },
+{  9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
+{  5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} },
+{  6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} },
+{ 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} },
+{ 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} },
+{  6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} },
+{  5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} },
+{  4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} },
+{ 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} },
+{ 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
+{  3, 0x0a1a, 0, {0x05,0xd0,0x04} },
+{  5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} },
+{  4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} },
+{ 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} },
+{ 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
+{  3, 0x0a3c, 0, {0x05,0xd0,0x04} },
+{ 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} },
+{ 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} },
+{ 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} },
+{  8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} },
+{  8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} },
+{ 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} },
+{  5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} },
+{  5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} },
+{  5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} },
+{ 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} },
+{  1, 0x0a9f, 0, {0x00} },
+{  7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} },
+{ 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} },
+{ 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
+{  9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} },
+{  3, 0x0ac8, 0, {0x02,0x0b,0x36} },
+{  5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} },
+{  3, 0x0ad0, 0, {0xbb,0x64,0x00} },
+{  2, 0x0ad3, 0, {0x50,0x1c} },
+{ 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{ 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} },
+{  1, 0x0af0, 0, {0xdf} },
+{ 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} },
+{ 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} },
+{ 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} },
+{  9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} },
+{ 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
+{ 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} },
+{  3, 0x0b36, 0, {0xba,0x2a,0x3b} },
+{ 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
+{ 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} },
+{  2, 0x0b54, 0, {0x7b,0x00} },
+{  3, 0x0b56, 0, {0xbb,0x0a,0x00} },
+{  5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} },
+{ 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{  8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} },
+{  3, 0x0b74, 0, {0xba,0x2b,0x1a} },
+{  8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} },
+{ 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0b91, 0, {0xba,0x10,0x1f} },
+{ 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} },
+{ 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
+{  3, 0x0bb0, 0, {0x02,0x0c,0x2d} },
+{  3, 0x0bb3, 0, {0xba,0x11,0x12} },
+{ 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0bc8, 0, {0xba,0x12,0x12} },
+{ 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0bdd, 0, {0xba,0x13,0x0b} },
+{ 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} },
+{  3, 0x0beb, 0, {0xba,0x14,0x11} },
+{ 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} },
+{  3, 0x0bfc, 0, {0x02,0x80,0x2e} },
+{  3, 0x0bff, 0, {0xba,0x15,0x1d} },
+{ 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} },
+{ 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} },
+{  3, 0x0c1c, 0, {0x02,0x80,0x0e} },
+{  3, 0x0c1f, 0, {0xba,0x16,0x0b} },
+{ 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} },
+{ 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} },
+{  1, 0x0c38, 0, {0x22} },
+{  7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} },
+{  7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} },
+{  6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} },
+{ 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} },
+{ 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} },
+{  6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} },
+{  3, 0x0c97, 0, {0x02,0x0d,0x38} },
+{  3, 0x0c9a, 0, {0xba,0x80,0x14} },
+{ 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} },
+{  6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} },
+{  5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} },
+{  3, 0x0cb6, 0, {0x02,0x0d,0x1d} },
+{  8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} },
+{  2, 0x0cc1, 0, {0x40,0x21} },
+{  6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} },
+{ 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
+{ 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} },
+{  3, 0x0ce4, 0, {0xbc,0x81,0x00} },
+{  2, 0x0ce7, 0, {0x40,0x21} },
+{  6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} },
+{ 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
+{ 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} },
+{  5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} },
+{ 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} },
+{  5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} },
+{  3, 0x0d22, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} },
+{  5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} },
+{  3, 0x0d38, 0, {0xbb,0x01,0x2d} },
+{  6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
+{  3, 0x0d41, 0, {0xba,0x02,0x11} },
+{ 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
+{  4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} },
+{  5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} },
+{  3, 0x0d5a, 0, {0x02,0x0e,0xcd} },
+{ 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} },
+{  3, 0x0d68, 0, {0xbb,0x03,0x1f} },
+{  6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
+{  5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} },
+{  3, 0x0d76, 0, {0x02,0x0e,0xcd} },
+{ 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
+{  4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} },
+{  3, 0x0d8a, 0, {0xbb,0x06,0x54} },
+{  5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} },
+{  3, 0x0d92, 0, {0x02,0x0e,0xc5} },
+{  8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} },
+{ 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
+{  9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
+{ 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} },
+{  3, 0x0dbc, 0, {0x02,0x0e,0xc5} },
+{ 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} },
+{  3, 0x0dc9, 0, {0x02,0x0e,0xc5} },
+{ 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
+{  9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
+{  6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} },
+{  3, 0x0de7, 0, {0xbb,0x08,0x10} },
+{ 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
+{  3, 0x0df7, 0, {0x02,0x0e,0xcd} },
+{  3, 0x0dfa, 0, {0xbb,0x09,0x31} },
+{  5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} },
+{  3, 0x0e02, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} },
+{  8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} },
+{ 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} },
+{  9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} },
+{  3, 0x0e2e, 0, {0xbb,0x0a,0x27} },
+{  5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} },
+{  3, 0x0e36, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} },
+{ 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
+{  3, 0x0e55, 0, {0x02,0x0e,0xcd} },
+{  5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} },
+{  3, 0x0e5d, 0, {0x02,0x0e,0xa9} },
+{ 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} },
+{  8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} },
+{ 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} },
+{  4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} },
+{  8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} },
+{  8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} },
+{ 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} },
+{  5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} },
+{  5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} },
+{  5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} },
+{  5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} },
+{  5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} },
+{  3, 0x0ebd, 0, {0xbb,0x84,0x05} },
+{  5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} },
+{  8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} },
+{  6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} },
+{  2, 0x0ed3, 0, {0xd0,0x86} },
+{ 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} },
+{  7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} },
+{ 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} },
+{  9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} },
+{  7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} },
+{  7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} },
+{ 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} },
+{  7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} },
+{  1, 0x0f3a, 0, {0x22} },
+{ 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} },
+{ 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} },
+{ 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} },
+{ 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} },
+{ 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} },
+{ 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} },
+{ 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} },
+{ 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} },
+{ 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} },
+{ 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} },
+{ 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} },
+{ 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} },
+{ 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} },
+{ 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} },
+{ 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} },
+{ 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} },
+{  4, 0x1017, 0, {0x00,0x03,0x01,0x00} },
+{  2, 0x101b, 0, {0x7a,0x00} },
+{  3, 0x101d, 0, {0xba,0x05,0x00} },
+{  2, 0x1020, 0, {0x50,0x17} },
+{  8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} },
+{  5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} },
+{ 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} },
+{  3, 0x1039, 0, {0x90,0x00,0x01} },
+{  1, 0x103c, 0, {0x22} },
+{ 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} },
+{  4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} },
+{ 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} },
+{  4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} },
+{  8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} },
+{  1, 0x1069, 0, {0x22} },
+{ 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} },
+{  4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} },
+{ 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} },
+{  4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} },
+{  1, 0x108e, 0, {0x22} },
+{ 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} },
+{ 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} },
+{  5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} },
+{ 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} },
+{  6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} },
+{  6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} },
+{  1, 0x10c9, 0, {0x22} },
+{  8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} },
+{  3, 0x10d2, 0, {0xba,0xff,0x00} },
+{  2, 0x10d5, 0, {0x50,0x0a} },
+{ 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
+{  1, 0x10e1, 0, {0x22} },
+{  5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} },
+{  8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} },
+{  6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} },
+{  4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} },
+{ 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} },
+{  5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x1109, 0, {0x80,0xee} },
+{  1, 0x110b, 0, {0x22} },
+{ 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} },
+{  3, 0x1116, 0, {0xba,0x28,0x00} },
+{  2, 0x1119, 0, {0x50,0x03} },
+{  3, 0x111b, 0, {0x0a,0x80,0xf8} },
+{  5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} },
+{  8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} },
+{  5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} },
+{  9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} },
+{  2, 0x1139, 0, {0x7a,0x00} },
+{  3, 0x113b, 0, {0xba,0x28,0x00} },
+{  2, 0x113e, 0, {0x50,0x03} },
+{  3, 0x1140, 0, {0x0a,0x80,0xf8} },
+{  1, 0x1143, 0, {0x22} },
+{  4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} },
+{  2, 0x1148, 0, {0x80,0x07} },
+{  7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} },
+{  5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} },
+{  9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} },
+{ 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} },
+{  8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} },
+{  3, 0x1171, 0, {0x0a,0x80,0xf5} },
+{  1, 0x1174, 0, {0x22} },
+{  6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} },
+{ 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} },
+{ 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} },
+{  9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x119d, 0, {0x80,0xdc} },
+{  1, 0x119f, 0, {0x22} },
+{ 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} },
+{  2, 0x11ad, 0, {0x50,0x06} },
+{  6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
+{  4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} },
+{ 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} },
+{  8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} },
+{  6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
+{  4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} },
+{  5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} },
+{  1, 0x11dc, 0, {0x22} },
+{  7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} },
+{ 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} },
+{  3, 0x11f0, 0, {0x12,0x11,0x44} },
+{ 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} },
+{  5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} },
+{  1, 0x1204, 0, {0x22} },
+{  2, 0x1205, 0, {0x7a,0x04} },
+{  3, 0x1207, 0, {0xba,0x40,0x00} },
+{  2, 0x120a, 0, {0x50,0x36} },
+{ 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} },
+{  3, 0x121a, 0, {0xbc,0x08,0x00} },
+{  2, 0x121d, 0, {0x50,0x20} },
+{  6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} },
+{ 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} },
+{  8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} },
+{  7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} },
+{  3, 0x123f, 0, {0x0a,0x80,0xc5} },
+{  1, 0x1242, 0, {0x22} },
+{  4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} },
+{  3, 0x1247, 0, {0xba,0x10,0x00} },
+{  2, 0x124a, 0, {0x50,0x20} },
+{ 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} },
+{ 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} },
+{  4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} },
+{  1, 0x126c, 0, {0x22} },
+{ 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{  1, 0x12b3, 0, {0x22} },
+{ 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} },
+{ 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} },
+{ 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} },
+{ 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} },
+{ 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} },
+{ 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} },
+{ 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} },
+{ 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} },
+{ 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} },
+{ 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} },
+{ 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} },
+{ 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} },
+{  3, 0x135c, 0, {0xbd,0x06,0x00} },
+{  2, 0x135f, 0, {0x50,0x12} },
+{ 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
+{  7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} },
+{ 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} },
+{ 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} },
+{ 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} },
+{  6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} },
+{  1, 0x13a2, 0, {0x22} },
+{ 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} },
+{ 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} },
+{  3, 0x13be, 0, {0xfa,0x7b,0x00} },
+{  3, 0x13c1, 0, {0xbb,0x10,0x00} },
+{  2, 0x13c4, 0, {0x50,0x24} },
+{ 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} },
+{ 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} },
+{  8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} },
+{ 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} },
+{  5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} },
+{  1, 0x13fd, 0, {0x22} },
+{  4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} },
+{  2, 0x1402, 0, {0x80,0x16} },
+{ 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} },
+{ 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} },
+{ 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} },
+{  6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} },
+{  6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} },
+{ 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} },
+{  1, 0x143b, 0, {0xe4} },
+{  3, 0x143c, 0, {0xfa,0x70,0x0f} },
+{ 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} },
+{  3, 0x144b, 0, {0x02,0x80,0x0a} },
+{ 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} },
+{ 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} },
+{  4, 0x1464, 0, {0x02,0xea,0x70,0x1a} },
+{ 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} },
+{  9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} },
+{  4, 0x147e, 0, {0x11,0x75,0x80,0x36} },
+{  2, 0x1482, 0, {0x7a,0x00} },
+{  3, 0x1484, 0, {0xba,0x10,0x00} },
+{  2, 0x1487, 0, {0x50,0x2f} },
+{ 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} },
+{  4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} },
+{ 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} },
+{  9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} },
+{  4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} },
+{  3, 0x14b5, 0, {0x0a,0x80,0xcc} },
+{  1, 0x14b8, 0, {0x22} },
+{  6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} },
+{ 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} },
+{  7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} },
+{  7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} },
+{  5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} },
+{  4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} },
+{  5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} },
+{  4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} },
+{  1, 0x14ed, 0, {0x22} },
+{ 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} },
+{  6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} },
+{  5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} },
+{  3, 0x1507, 0, {0xe0,0x80,0x07} },
+{  4, 0x150a, 0, {0xe4,0x93,0x80,0x03} },
+{  3, 0x150e, 0, {0xa8,0x82,0xe2} },
+{  4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} },
+{  1, 0x1515, 0, {0x22} },
+{  0, 0x0000, 1, {0} }
+
+};
+
+static unsigned char bitstream[] = {
+
+0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D,
+0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B,
+0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39,
+0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34,
+0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B,
+0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F,
+0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF,
+0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF,
+0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE,
+0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF,
+0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF,
+0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF,
+0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD,
+0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,
+0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF,
+0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D,
+0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE,
+0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF,
+0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F,
+0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F,
+0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF,
+0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F,
+0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F,
+0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2,
+0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF,
+0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE,
+0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF,
+0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF,
+0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B,
+0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF,
+0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7,
+0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF,
+0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF,
+0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5,
+0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD,
+0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF,
+0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF,
+0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B,
+0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF,
+0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED,
+0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF,
+0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB,
+0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF,
+0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE,
+0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7,
+0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE,
+0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF,
+0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD,
+0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD,
+0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF,
+0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD,
+0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A,
+0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF,
+0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF,
+0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA,
+0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF,
+0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD,
+0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF,
+0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,
+0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E,
+0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF,
+0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF,
+0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF,
+0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3,
+0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF,
+0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F,
+0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF,
+0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF,
+0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7,
+0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF,
+0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD,
+0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD,
+0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE,
+0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF,
+0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF,
+0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3,
+0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A,
+0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF,
+0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB,
+0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF,
+0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD,
+0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF,
+0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,
+0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F,
+0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
+0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F,
+0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
+0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED,
+0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7,
+0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7,
+0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF,
+0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F,
+0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE,
+0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
+0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA,
+0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F,
+0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA,
+0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB,
+0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF,
+0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB,
+0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF,
+0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF,
+0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD,
+0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C,
+0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF,
+0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF,
+0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD,
+0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF,
+0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3,
+0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB,
+0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F,
+0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3,
+0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF,
+0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7,
+0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7,
+0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF,
+0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE,
+0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF,
+0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB,
+0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66,
+0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE,
+0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6,
+0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED,
+0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD,
+0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7,
+0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF,
+0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB,
+0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF,
+0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F,
+0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7,
+0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9,
+0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF,
+0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF,
+0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE,
+0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF,
+0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF,
+0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF,
+0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD,
+0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1,
+0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF,
+0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5,
+0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF,
+0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB,
+0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF,
+0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF,
+0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3,
+0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE,
+0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD,
+0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE,
+0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF,
+0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF,
+0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB,
+0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF,
+0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF,
+0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF,
+0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F,
+0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C,
+0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD,
+0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF,
+0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F,
+0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE,
+0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD,
+0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54,
+0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2,
+0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD,
+0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF,
+0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF,
+0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7,
+0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA,
+0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF,
+0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C,
+0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF,
+0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5,
+0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB,
+0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF,
+0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF,
+0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F,
+0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F,
+0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF,
+0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF,
+0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5,
+0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF,
+0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF,
+0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A,
+0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36,
+0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF,
+0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F,
+0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F,
+0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF,
+0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF,
+0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF,
+0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF,
+0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE,
+0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,
+0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF,
+0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F,
+0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B,
+0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB,
+0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF,
+0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF,
+0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA,
+0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37,
+0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD,
+0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B,
+0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF,
+0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B,
+0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B,
+0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF,
+0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD,
+0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF,
+0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE,
+0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF,
+0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF,
+0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA,
+0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E,
+0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF,
+0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF,
+0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6,
+0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD,
+0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB,
+0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F,
+0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F,
+0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7,
+0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB,
+0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD,
+0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E,
+0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF,
+0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE,
+0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF,
+0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF,
+0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE,
+0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2,
+0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF,
+0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF,
+0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF,
+0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC,
+0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF,
+0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7,
+0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7,
+0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3,
+0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9,
+0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF,
+0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,
+0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F,
+0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B,
+0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE,
+0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79,
+0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F,
+0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7,
+0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC,
+0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7,
+0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF,
+0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,
+0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F,
+0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE,
+0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF,
+0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F,
+0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7,
+0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7,
+0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF,
+0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,
+0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD,
+0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF,
+0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB,
+0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE,
+0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3,
+0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF,
+0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF,
+0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE,
+0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6,
+0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF,
+0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF,
+0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F,
+0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE,
+0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6,
+0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77,
+0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF,
+0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A,
+0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F,
+0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F,
+0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF,
+0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB,
+0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F,
+0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67,
+0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF,
+0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D,
+0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3,
+0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D,
+0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB,
+0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE,
+0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5,
+0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D,
+0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F,
+0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB,
+0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB,
+0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9,
+0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF,
+0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF,
+0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF,
+0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77,
+0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F,
+0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE,
+0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
+0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF,
+0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD,
+0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F,
+0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A,
+0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA,
+0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF,
+0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF,
+0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF,
+0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF,
+0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF,
+0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9,
+0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F,
+0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7,
+0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4,
+0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9,
+0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF,
+0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7,
+0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF,
+0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF,
+0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF,
+0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5,
+0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF,
+0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD,
+0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77,
+0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE,
+0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF,
+0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF,
+0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC,
+0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB,
+0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F,
+0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6,
+0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD,
+0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF,
+0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC,
+0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,
+0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E,
+0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F,
+0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB,
+0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF,
+0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7,
+0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F,
+0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2,
+0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA,
+0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF,
+0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8,
+0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB,
+0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF,
+0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB,
+0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF,
+0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF,
+0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7,
+0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3,
+0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F,
+0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD,
+0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF,
+0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
+0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF,
+0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F,
+0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF,
+0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F,
+0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF,
+0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7,
+0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9,
+0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71,
+0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF,
+0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF,
+0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F,
+0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7,
+0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC,
+0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE,
+0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7,
+0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF,
+0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB,
+0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B,
+0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF,
+0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF,
+0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE,
+0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17,
+0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9,
+0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F,
+0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE,
+0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,
+0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F,
+0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF,
+0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF,
+0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F,
+0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF,
+0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5,
+0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA,
+0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE,
+0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF,
+0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA,
+0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3,
+0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,
+0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7,
+0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
+0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF,
+0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB,
+0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9,
+0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF,
+0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD,
+0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE,
+0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE,
+0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB,
+0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB,
+0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB,
+0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF,
+0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF,
+0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77,
+0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE,
+0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8,
+0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E,
+0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3,
+0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,
+0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7,
+0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB,
+0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF,
+0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF,
+0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF,
+0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3,
+0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F,
+0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F,
+0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF,
+0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,
+0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF,
+0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF,
+0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD,
+0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE,
+0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1,
+0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF,
+0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC,
+0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF,
+0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB,
+0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9,
+0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E,
+0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF,
+0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,
+0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,
+0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF,
+0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7,
+0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF,
+0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F,
+0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF,
+0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF,
+0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF,
+0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3,
+0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC,
+0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF,
+0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF,
+0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF,
+0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF,
+0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF,
+0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF,
+0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF,
+0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF,
+0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF,
+0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB,
+0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F,
+0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF,
+0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD,
+0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD,
+0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE,
+0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF,
+0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5,
+0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F,
+0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF,
+0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE,
+0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF,
+0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF,
+0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF,
+0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB,
+0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7,
+0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF,
+0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F,
+0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
+0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF,
+0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB,
+0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF,
+0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF,
+0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF,
+0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,
+0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,
+0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE,
+0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE,
+0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4,
+0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC,
+0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF,
+0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7,
+0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65,
+0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3,
+0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,
+0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB,
+0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF,
+0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B,
+0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF,
+0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF,
+0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF,
+0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7,
+0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF,
+0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9,
+0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,
+0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF,
+0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF,
+0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A,
+0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7,
+0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF,
+0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD,
+0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC,
+0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA,
+0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D,
+0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF,
+0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6,
+0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
+0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF,
+0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF,
+0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF,
+0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF,
+0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB,
+0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E,
+0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF,
+0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF,
+0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF,
+0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16,
+0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF,
+0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7,
+0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9,
+0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF,
+0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F,
+0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A,
+0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE,
+0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB,
+0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB,
+0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3,
+0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF,
+0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE,
+0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB,
+0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF,
+0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE,
+0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5,
+0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF,
+0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD,
+0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F,
+0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7,
+0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
+0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA,
+0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD,
+0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA,
+0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33,
+0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9,
+0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF,
+0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77,
+0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF,
+0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F,
+0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF,
+0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF,
+0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7,
+0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,
+0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB,
+0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF,
+0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD,
+0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE,
+0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF,
+0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F,
+0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B,
+0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9,
+0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD,
+0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF,
+0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB,
+0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF,
+0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF,
+0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF,
+0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9,
+0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF,
+0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD,
+0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE,
+0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF,
+0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF,
+0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE,
+0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE,
+0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF,
+0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF,
+0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF,
+0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF,
+0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF,
+0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF,
+0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD,
+0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF,
+0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F,
+0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF,
+0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE,
+0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB,
+0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF,
+0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF,
+0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5,
+0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF,
+0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF,
+0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB,
+0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7,
+0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF,
+0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE,
+0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB,
+0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB,
+0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF,
+0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7,
+0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F,
+0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF,
+0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF,
+0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F,
+0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD,
+0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF,
+0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF,
+0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF,
+0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7,
+0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,
+0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,
+0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC,
+0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC,
+0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF,
+0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF,
+0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB,
+0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD,
+0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF
+
+};
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
new file mode 100644 (file)
index 0000000..b9ba95f
--- /dev/null
@@ -0,0 +1,874 @@
+/*****************************************************************************/
+
+/*
+ *      dabusb.c  --  dab usb driver.
+ *
+ *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.de)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *  $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+
+#include "dabusb.h"
+#include "dabfirmware.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.54"
+#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
+#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
+
+/* --------------------------------------------------------------------- */
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define NRDABUSB 256
+#else
+#define NRDABUSB 4
+#endif
+
+/*-------------------------------------------------------------------*/
+
+static dabusb_t dabusb[NRDABUSB];
+static int buffers = 256;
+static struct usb_driver dabusb_driver;
+
+/*-------------------------------------------------------------------*/
+
+static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src)
+{
+       unsigned long flags;
+       struct list_head *tmp;
+       int ret = 0;
+
+       spin_lock_irqsave (&s->lock, flags);
+
+       if (list_empty (src)) {
+               // no elements in source buffer
+               ret = -1;
+               goto err;
+       }
+       tmp = src->next;
+       list_move_tail (tmp, dst);
+
+  err: spin_unlock_irqrestore (&s->lock, flags);
+       return ret;
+}
+/*-------------------------------------------------------------------*/
+#ifdef DEBUG
+static void dump_urb (struct urb *urb)
+{
+       dbg("urb                   :%p", urb);
+       dbg("dev                   :%p", urb->dev);
+       dbg("pipe                  :%08X", urb->pipe);
+       dbg("status                :%d", urb->status);
+       dbg("transfer_flags        :%08X", urb->transfer_flags);
+       dbg("transfer_buffer       :%p", urb->transfer_buffer);
+       dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
+       dbg("actual_length         :%d", urb->actual_length);
+       dbg("setup_packet          :%p", urb->setup_packet);
+       dbg("start_frame           :%d", urb->start_frame);
+       dbg("number_of_packets     :%d", urb->number_of_packets);
+       dbg("interval              :%d", urb->interval);
+       dbg("error_count           :%d", urb->error_count);
+       dbg("context               :%p", urb->context);
+       dbg("complete              :%p", urb->complete);
+}
+#endif
+/*-------------------------------------------------------------------*/
+static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
+{
+       unsigned long flags;
+       pbuff_t b;
+
+       dbg("dabusb_cancel_queue");
+
+       spin_lock_irqsave (&s->lock, flags);
+
+       list_for_each_entry(b, q, buff_list) {
+#ifdef DEBUG
+               dump_urb(b->purb);
+#endif
+               usb_unlink_urb (b->purb);
+       }
+       spin_unlock_irqrestore (&s->lock, flags);
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_free_queue (struct list_head *q)
+{
+       struct list_head *tmp;
+       struct list_head *p;
+       pbuff_t b;
+
+       dbg("dabusb_free_queue");
+       for (p = q->next; p != q;) {
+               b = list_entry (p, buff_t, buff_list);
+
+#ifdef DEBUG
+               dump_urb(b->purb);
+#endif
+               kfree(b->purb->transfer_buffer);
+               usb_free_urb(b->purb);
+               tmp = p->next;
+               list_del (p);
+               kfree (b);
+               p = tmp;
+       }
+
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_free_buffers (pdabusb_t s)
+{
+       unsigned long flags;
+       dbg("dabusb_free_buffers");
+
+       spin_lock_irqsave(&s->lock, flags);
+
+       dabusb_free_queue (&s->free_buff_list);
+       dabusb_free_queue (&s->rec_buff_list);
+
+       spin_unlock_irqrestore(&s->lock, flags);
+
+       s->got_mem = 0;
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)
+{
+       pbuff_t b = purb->context;
+       pdabusb_t s = b->s;
+       int i;
+       int len;
+       int dst = 0;
+       void *buf = purb->transfer_buffer;
+
+       dbg("dabusb_iso_complete");
+
+       // process if URB was not killed
+       if (purb->status != -ENOENT) {
+               unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
+               int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+               for (i = 0; i < purb->number_of_packets; i++)
+                       if (!purb->iso_frame_desc[i].status) {
+                               len = purb->iso_frame_desc[i].actual_length;
+                               if (len <= pipesize) {
+                                       memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);
+                                       dst += len;
+                               }
+                               else
+                                       err("dabusb_iso_complete: invalid len %d", len);
+                       }
+                       else
+                               warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status);
+               if (dst != purb->actual_length)
+                       err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
+       }
+
+       if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
+               s->overruns++;
+               err("overrun (%d)", s->overruns);
+       }
+       wake_up (&s->wait);
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_alloc_buffers (pdabusb_t s)
+{
+       int buffers = 0;
+       pbuff_t b;
+       unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
+       int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
+       int packets = _ISOPIPESIZE / pipesize;
+       int transfer_buffer_length = packets * pipesize;
+       int i;
+
+       dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
+                pipesize, packets, transfer_buffer_length);
+
+       while (buffers < (s->total_buffer_size << 10)) {
+               b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
+               if (!b) {
+                       err("kzalloc(sizeof(buff_t))==NULL");
+                       goto err;
+               }
+               b->s = s;
+               b->purb = usb_alloc_urb(packets, GFP_KERNEL);
+               if (!b->purb) {
+                       err("usb_alloc_urb == NULL");
+                       kfree (b);
+                       goto err;
+               }
+
+               b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);
+               if (!b->purb->transfer_buffer) {
+                       kfree (b->purb);
+                       kfree (b);
+                       err("kmalloc(%d)==NULL", transfer_buffer_length);
+                       goto err;
+               }
+
+               b->purb->transfer_buffer_length = transfer_buffer_length;
+               b->purb->number_of_packets = packets;
+               b->purb->complete = dabusb_iso_complete;
+               b->purb->context = b;
+               b->purb->dev = s->usbdev;
+               b->purb->pipe = pipe;
+               b->purb->transfer_flags = URB_ISO_ASAP;
+
+               for (i = 0; i < packets; i++) {
+                       b->purb->iso_frame_desc[i].offset = i * pipesize;
+                       b->purb->iso_frame_desc[i].length = pipesize;
+               }
+
+               buffers += transfer_buffer_length;
+               list_add_tail (&b->buff_list, &s->free_buff_list);
+       }
+       s->got_mem = buffers;
+
+       return 0;
+
+       err:
+       dabusb_free_buffers (s);
+       return -ENOMEM;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
+{
+       int ret;
+       unsigned int pipe;
+       int actual_length;
+
+       dbg("dabusb_bulk");
+
+       if (!pb->pipe)
+               pipe = usb_rcvbulkpipe (s->usbdev, 2);
+       else
+               pipe = usb_sndbulkpipe (s->usbdev, 2);
+
+       ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
+       if(ret<0) {
+               err("dabusb: usb_bulk_msg failed(%d)",ret);
+
+               if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+                       err("set_interface failed");
+                       return -EINVAL;
+               }
+
+       }
+
+       if( ret == -EPIPE ) {
+               warn("CLEAR_FEATURE request to remove STALL condition.");
+               if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
+                       err("request failed");
+       }
+
+       pb->size = actual_length;
+       return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len)
+{
+       int ret;
+       unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);
+
+       if (!transfer_buffer) {
+               err("dabusb_writemem: kmalloc(%d) failed.", len);
+               return -ENOMEM;
+       }
+
+       memcpy (transfer_buffer, data, len);
+
+       ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
+
+       kfree (transfer_buffer);
+       return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit)
+{
+       dbg("dabusb_8051_reset: %d",reset_bit);
+       return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_loadmem (pdabusb_t s, const char *fname)
+{
+       int ret;
+       PINTEL_HEX_RECORD ptr = firmware;
+
+       dbg("Enter dabusb_loadmem (internal)");
+
+       ret = dabusb_8051_reset (s, 1);
+       while (ptr->Type == 0) {
+
+               dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length);
+
+               ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length);
+               if (ret < 0) {
+                       err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length);
+                       break;
+               }
+               ptr++;
+       }
+       ret = dabusb_8051_reset (s, 0);
+
+       dbg("dabusb_loadmem: exit");
+
+       return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b)
+{
+       b->size = 4;
+       b->data[0] = 0x2a;
+       b->data[1] = 0;
+       b->data[2] = 0;
+       b->data[3] = 0;
+
+       dbg("dabusb_fpga_clear");
+
+       return dabusb_bulk (s, b);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b)
+{
+       b->size = 4;
+       b->data[0] = 0x2c;
+       b->data[1] = 0;
+       b->data[2] = 0;
+       b->data[3] = 0;
+
+       dbg("dabusb_fpga_init");
+
+       return dabusb_bulk (s, b);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_download (pdabusb_t s, const char *fname)
+{
+       pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+       unsigned int blen, n;
+       int ret;
+       unsigned char *buf = bitstream;
+
+       dbg("Enter dabusb_fpga_download (internal)");
+
+       if (!b) {
+               err("kmalloc(sizeof(bulk_transfer_t))==NULL");
+               return -ENOMEM;
+       }
+
+       b->pipe = 1;
+       ret = dabusb_fpga_clear (s, b);
+       mdelay (10);
+       blen = buf[73] + (buf[72] << 8);
+
+       dbg("Bitstream len: %i", blen);
+
+       b->data[0] = 0x2b;
+       b->data[1] = 0;
+       b->data[2] = 0;
+       b->data[3] = 60;
+
+       for (n = 0; n <= blen + 60; n += 60) {
+               // some cclks for startup
+               b->size = 64;
+               memcpy (b->data + 4, buf + 74 + n, 60);
+               ret = dabusb_bulk (s, b);
+               if (ret < 0) {
+                       err("dabusb_bulk failed.");
+                       break;
+               }
+               mdelay (1);
+       }
+
+       ret = dabusb_fpga_init (s, b);
+       kfree (b);
+
+       dbg("exit dabusb_fpga_download");
+
+       return ret;
+}
+
+static int dabusb_stop (pdabusb_t s)
+{
+       dbg("dabusb_stop");
+
+       s->state = _stopped;
+       dabusb_cancel_queue (s, &s->rec_buff_list);
+
+       dbg("pending_io: %d", s->pending_io.counter);
+
+       s->pending_io.counter = 0;
+       return 0;
+}
+
+static int dabusb_startrek (pdabusb_t s)
+{
+       if (!s->got_mem && s->state != _started) {
+
+               dbg("dabusb_startrek");
+
+               if (dabusb_alloc_buffers (s) < 0)
+                       return -ENOMEM;
+               dabusb_stop (s);
+               s->state = _started;
+               s->readptr = 0;
+       }
+
+       if (!list_empty (&s->free_buff_list)) {
+               pbuff_t end;
+               int ret;
+
+       while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) {
+
+                       dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
+
+                       end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
+
+                       ret = usb_submit_urb (end->purb, GFP_KERNEL);
+                       if (ret) {
+                               err("usb_submit_urb returned:%d", ret);
+                               if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+                                       err("startrek: dabusb_add_buf_tail failed");
+                               break;
+                       }
+                       else
+                               atomic_inc (&s->pending_io);
+               }
+               dbg("pending_io: %d",s->pending_io.counter);
+       }
+
+       return 0;
+}
+
+static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
+{
+       pdabusb_t s = (pdabusb_t) file->private_data;
+       unsigned long flags;
+       unsigned ret = 0;
+       int rem;
+       int cnt;
+       pbuff_t b;
+       struct urb *purb = NULL;
+
+       dbg("dabusb_read");
+
+       if (*ppos)
+               return -ESPIPE;
+
+       if (s->remove_pending)
+               return -EIO;
+
+
+       if (!s->usbdev)
+               return -EIO;
+
+       while (count > 0) {
+               dabusb_startrek (s);
+
+               spin_lock_irqsave (&s->lock, flags);
+
+               if (list_empty (&s->rec_buff_list)) {
+
+                       spin_unlock_irqrestore(&s->lock, flags);
+
+                       err("error: rec_buf_list is empty");
+                       goto err;
+               }
+
+               b = list_entry (s->rec_buff_list.next, buff_t, buff_list);
+               purb = b->purb;
+
+               spin_unlock_irqrestore(&s->lock, flags);
+
+               if (purb->status == -EINPROGRESS) {
+                       if (file->f_flags & O_NONBLOCK)         // return nonblocking
+                        {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               goto err;
+                       }
+
+                       interruptible_sleep_on (&s->wait);
+
+                       if (signal_pending (current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               goto err;
+                       }
+
+                       spin_lock_irqsave (&s->lock, flags);
+
+                       if (list_empty (&s->rec_buff_list)) {
+                               spin_unlock_irqrestore(&s->lock, flags);
+                               err("error: still no buffer available.");
+                               goto err;
+                       }
+                       spin_unlock_irqrestore(&s->lock, flags);
+                       s->readptr = 0;
+               }
+               if (s->remove_pending) {
+                       ret = -EIO;
+                       goto err;
+               }
+
+               rem = purb->actual_length - s->readptr;         // set remaining bytes to copy
+
+               if (count >= rem)
+                       cnt = rem;
+               else
+                       cnt = count;
+
+               dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
+
+               if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
+                       err("read: copy_to_user failed");
+                       if (!ret)
+                               ret = -EFAULT;
+                       goto err;
+               }
+
+               s->readptr += cnt;
+               count -= cnt;
+               buf += cnt;
+               ret += cnt;
+
+               if (s->readptr == purb->actual_length) {
+                       // finished, take next buffer
+                       if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+                               err("read: dabusb_add_buf_tail failed");
+                       s->readptr = 0;
+               }
+       }
+      err:                     //mutex_unlock(&s->mutex);
+       return ret;
+}
+
+static int dabusb_open (struct inode *inode, struct file *file)
+{
+       int devnum = iminor(inode);
+       pdabusb_t s;
+
+       if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
+               return -EIO;
+
+       s = &dabusb[devnum - DABUSB_MINOR];
+
+       dbg("dabusb_open");
+       mutex_lock(&s->mutex);
+
+       while (!s->usbdev || s->opened) {
+               mutex_unlock(&s->mutex);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       return -EBUSY;
+               }
+               msleep_interruptible(500);
+
+               if (signal_pending (current)) {
+                       return -EAGAIN;
+               }
+               mutex_lock(&s->mutex);
+       }
+       if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+               mutex_unlock(&s->mutex);
+               err("set_interface failed");
+               return -EINVAL;
+       }
+       s->opened = 1;
+       mutex_unlock(&s->mutex);
+
+       file->f_pos = 0;
+       file->private_data = s;
+
+       return nonseekable_open(inode, file);
+}
+
+static int dabusb_release (struct inode *inode, struct file *file)
+{
+       pdabusb_t s = (pdabusb_t) file->private_data;
+
+       dbg("dabusb_release");
+
+       mutex_lock(&s->mutex);
+       dabusb_stop (s);
+       dabusb_free_buffers (s);
+       mutex_unlock(&s->mutex);
+
+       if (!s->remove_pending) {
+               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
+                       err("set_interface failed");
+       }
+       else
+               wake_up (&s->remove_ok);
+
+       s->opened = 0;
+       return 0;
+}
+
+static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       pdabusb_t s = (pdabusb_t) file->private_data;
+       pbulk_transfer_t pbulk;
+       int ret = 0;
+       int version = DABUSB_VERSION;
+
+       dbg("dabusb_ioctl");
+
+       if (s->remove_pending)
+               return -EIO;
+
+       mutex_lock(&s->mutex);
+
+       if (!s->usbdev) {
+               mutex_unlock(&s->mutex);
+               return -EIO;
+       }
+
+       switch (cmd) {
+
+       case IOCTL_DAB_BULK:
+               pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+
+               if (!pbulk) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
+                       ret = -EFAULT;
+                       kfree (pbulk);
+                       break;
+               }
+
+               ret=dabusb_bulk (s, pbulk);
+               if(ret==0)
+                       if (copy_to_user((void __user *)arg, pbulk,
+                                        sizeof(bulk_transfer_t)))
+                               ret = -EFAULT;
+               kfree (pbulk);
+               break;
+
+       case IOCTL_DAB_OVERRUNS:
+               ret = put_user (s->overruns, (unsigned int __user *) arg);
+               break;
+
+       case IOCTL_DAB_VERSION:
+               ret = put_user (version, (unsigned int __user *) arg);
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+       mutex_unlock(&s->mutex);
+       return ret;
+}
+
+static struct file_operations dabusb_fops =
+{
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+       .read =         dabusb_read,
+       .ioctl =        dabusb_ioctl,
+       .open =         dabusb_open,
+       .release =      dabusb_release,
+};
+
+static struct usb_class_driver dabusb_class = {
+       .name =         "dabusb%d",
+       .fops =         &dabusb_fops,
+       .minor_base =   DABUSB_MINOR,
+};
+
+
+/* --------------------------------------------------------------------- */
+static int dabusb_probe (struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+       int retval;
+       pdabusb_t s;
+
+       dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+           le16_to_cpu(usbdev->descriptor.idVendor),
+           le16_to_cpu(usbdev->descriptor.idProduct),
+           intf->altsetting->desc.bInterfaceNumber);
+
+       /* We don't handle multiple configurations */
+       if (usbdev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF &&
+           le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999)
+               return -ENODEV;
+
+
+
+       s = &dabusb[intf->minor];
+
+       mutex_lock(&s->mutex);
+       s->remove_pending = 0;
+       s->usbdev = usbdev;
+       s->devnum = intf->minor;
+
+       if (usb_reset_configuration (usbdev) < 0) {
+               err("reset_configuration failed");
+               goto reject;
+       }
+       if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
+               dabusb_loadmem (s, NULL);
+               goto reject;
+       }
+       else {
+               dabusb_fpga_download (s, NULL);
+
+               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
+                       err("set_interface failed");
+                       goto reject;
+               }
+       }
+       dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
+       usb_set_intfdata (intf, s);
+       mutex_unlock(&s->mutex);
+
+       retval = usb_register_dev(intf, &dabusb_class);
+       if (retval) {
+               usb_set_intfdata (intf, NULL);
+               return -ENOMEM;
+       }
+
+       return 0;
+
+      reject:
+       mutex_unlock(&s->mutex);
+       s->usbdev = NULL;
+       return -ENODEV;
+}
+
+static void dabusb_disconnect (struct usb_interface *intf)
+{
+       wait_queue_t __wait;
+       pdabusb_t s = usb_get_intfdata (intf);
+
+       dbg("dabusb_disconnect");
+
+       init_waitqueue_entry(&__wait, current);
+
+       usb_set_intfdata (intf, NULL);
+       if (s) {
+               usb_deregister_dev (intf, &dabusb_class);
+               s->remove_pending = 1;
+               wake_up (&s->wait);
+               add_wait_queue(&s->remove_ok, &__wait);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (s->state == _started)
+                       schedule();
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&s->remove_ok, &__wait);
+
+               s->usbdev = NULL;
+               s->overruns = 0;
+       }
+}
+
+static struct usb_device_id dabusb_ids [] = {
+       // { USB_DEVICE(0x0547, 0x2131) },      /* An2131 chip, no boot ROM */
+       { USB_DEVICE(0x0547, 0x9999) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dabusb_ids);
+
+static struct usb_driver dabusb_driver = {
+       .name =         "dabusb",
+       .probe =        dabusb_probe,
+       .disconnect =   dabusb_disconnect,
+       .id_table =     dabusb_ids,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int __init dabusb_init (void)
+{
+       int retval;
+       unsigned u;
+
+       /* initialize struct */
+       for (u = 0; u < NRDABUSB; u++) {
+               pdabusb_t s = &dabusb[u];
+               memset (s, 0, sizeof (dabusb_t));
+               mutex_init (&s->mutex);
+               s->usbdev = NULL;
+               s->total_buffer_size = buffers;
+               init_waitqueue_head (&s->wait);
+               init_waitqueue_head (&s->remove_ok);
+               spin_lock_init (&s->lock);
+               INIT_LIST_HEAD (&s->free_buff_list);
+               INIT_LIST_HEAD (&s->rec_buff_list);
+       }
+
+       /* register misc device */
+       retval = usb_register(&dabusb_driver);
+       if (retval)
+               goto out;
+
+       dbg("dabusb_init: driver registered");
+
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+
+out:
+       return retval;
+}
+
+static void __exit dabusb_cleanup (void)
+{
+       dbg("dabusb_cleanup");
+
+       usb_deregister (&dabusb_driver);
+}
+
+/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(buffers, int, 0);
+MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
+
+module_init (dabusb_init);
+module_exit (dabusb_cleanup);
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/media/video/dabusb.h b/drivers/media/video/dabusb.h
new file mode 100644 (file)
index 0000000..00eb34c
--- /dev/null
@@ -0,0 +1,85 @@
+#define _BULK_DATA_LEN 64
+typedef struct
+{
+       unsigned char data[_BULK_DATA_LEN];
+       unsigned int size;
+       unsigned int pipe;
+}bulk_transfer_t,*pbulk_transfer_t;
+
+#define DABUSB_MINOR 240               /* some unassigned USB minor */
+#define DABUSB_VERSION 0x1000
+#define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
+#define IOCTL_DAB_OVERRUNS         _IOR('d',  0x15, int)
+#define IOCTL_DAB_VERSION           _IOR('d', 0x3f, int)
+
+#ifdef __KERNEL__
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+       struct mutex mutex;
+       struct usb_device *usbdev;
+       wait_queue_head_t wait;
+       wait_queue_head_t remove_ok;
+       spinlock_t lock;
+       atomic_t pending_io;
+       driver_state_t state;
+       int remove_pending;
+       int got_mem;
+       int total_buffer_size;
+       unsigned int overruns;
+       int readptr;
+       int opened;
+       int devnum;
+       struct list_head free_buff_list;
+       struct list_head rec_buff_list;
+} dabusb_t,*pdabusb_t;
+
+typedef struct
+{
+       pdabusb_t s;
+       struct urb *purb;
+       struct list_head buff_list;
+} buff_t,*pbuff_t;
+
+typedef struct
+{
+       wait_queue_head_t wait;
+} bulk_completion_context_t, *pbulk_completion_context_t;
+
+
+#define _DABUSB_IF 2
+#define _DABUSB_ISOPIPE 0x09
+#define _ISOPIPESIZE   16384
+
+#define _BULK_DATA_LEN 64
+// Vendor specific request code for Anchor Upload/Download
+// This one is implemented in the core
+#define ANCHOR_LOAD_INTERNAL  0xA0
+
+// EZ-USB Control and Status Register.  Bit 0 controls 8051 reset
+#define CPUCS_REG    0x7F92
+#define _TOTAL_BUFFERS 384
+
+#define MAX_INTEL_HEX_RECORD_LENGTH 16
+
+#ifndef _BYTE_DEFINED
+#define _BYTE_DEFINED
+typedef unsigned char BYTE;
+#endif // !_BYTE_DEFINED
+
+#ifndef _WORD_DEFINED
+#define _WORD_DEFINED
+typedef unsigned short WORD;
+#endif // !_WORD_DEFINED
+
+typedef struct _INTEL_HEX_RECORD
+{
+   BYTE  Length;
+   WORD  Address;
+   BYTE  Type;
+   BYTE  Data[MAX_INTEL_HEX_RECORD_LENGTH];
+} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
+
+#endif
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c
new file mode 100644 (file)
index 0000000..3b4e998
--- /dev/null
@@ -0,0 +1,429 @@
+/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
+ into both the USB and an analog audio input, so this thing
+ only deals with initialisation and frequency setting, the
+ audio data has to be handled by a sound driver.
+
+ Major issue: I can't find out where the device reports the signal
+ strength, and indeed the windows software appearantly just looks
+ at the stereo indicator as well.  So, scanning will only find
+ stereo stations.  Sad, but I can't help it.
+
+ Also, the windows program sends oodles of messages over to the
+ device, and I couldn't figure out their meaning.  My suspicion
+ is that they don't have any:-)
+
+ You might find some interesting stuff about this module at
+ http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
+
+ Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ History:
+
+ Version 0.40:
+  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+
+ Version 0.30:
+       Markus: Updates for 2.5.x kernel and more ISO compliant source
+
+ Version 0.25:
+       PSL and Markus: Cleanup, radio now doesn't stop on device close
+
+ Version 0.24:
+       Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
+       right.  Some minor cleanup, improved standalone compilation
+
+ Version 0.23:
+       Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
+
+ Version 0.22:
+       Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
+       thanks to Mike Cox for pointing the problem out.
+
+ Version 0.21:
+       Markus: Minor cleanup, warnings if something goes wrong, lame attempt
+       to adhere to Documentation/CodingStyle
+
+ Version 0.2:
+       Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
+       Markus: Copyright clarification
+
+ Version 0.01: Markus: initial release
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.40"
+#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
+#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
+
+#define DSB100_VENDOR 0x04b4
+#define DSB100_PRODUCT 0x1002
+
+/* Commands the device appears to understand */
+#define DSB100_TUNE 1
+#define DSB100_ONOFF 2
+
+#define TB_LEN 16
+
+/* Frequency limits in MHz -- these are European values.  For Japanese
+devices, that would be 76 and 91.  */
+#define FREQ_MIN  87.5
+#define FREQ_MAX 108.0
+#define FREQ_MUL 16000
+
+
+static int usb_dsbr100_probe(struct usb_interface *intf,
+                            const struct usb_device_id *id);
+static void usb_dsbr100_disconnect(struct usb_interface *intf);
+static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg);
+static int usb_dsbr100_open(struct inode *inode, struct file *file);
+static int usb_dsbr100_close(struct inode *inode, struct file *file);
+
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+
+/* Data for one (physical) device */
+typedef struct {
+       struct usb_device *usbdev;
+       struct video_device *videodev;
+       unsigned char transfer_buffer[TB_LEN];
+       int curfreq;
+       int stereo;
+       int users;
+       int removed;
+} dsbr100_device;
+
+
+/* File system interface */
+static struct file_operations usb_dsbr100_fops = {
+       .owner =        THIS_MODULE,
+       .open =         usb_dsbr100_open,
+       .release =      usb_dsbr100_close,
+       .ioctl =        usb_dsbr100_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+
+/* V4L interface */
+static struct video_device dsbr100_videodev_template=
+{
+       .owner =        THIS_MODULE,
+       .name =         "D-Link DSB-R 100",
+       .type =         VID_TYPE_TUNER,
+       .hardware =     VID_HARDWARE_AZTECH,
+       .fops =         &usb_dsbr100_fops,
+       .release = video_device_release,
+};
+
+static struct usb_device_id usb_dsbr100_device_table [] = {
+       { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_dsbr100_driver = {
+       .name =         "dsbr100",
+       .probe =        usb_dsbr100_probe,
+       .disconnect =   usb_dsbr100_disconnect,
+       .id_table =     usb_dsbr100_device_table,
+};
+
+/* Low-level device interface begins here */
+
+/* switch on radio */
+static int dsbr100_start(dsbr100_device *radio)
+{
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
+       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       DSB100_ONOFF,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+               return -1;
+       return (radio->transfer_buffer)[0];
+}
+
+
+/* switch off radio */
+static int dsbr100_stop(dsbr100_device *radio)
+{
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
+       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       DSB100_ONOFF,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+               return -1;
+       return (radio->transfer_buffer)[0];
+}
+
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int dsbr100_setfreq(dsbr100_device *radio, int freq)
+{
+       freq = (freq/16*80)/1000+856;
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       DSB100_TUNE,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       (freq>>8)&0x00ff, freq&0xff,
+                       radio->transfer_buffer, 8, 300)<0 ||
+          usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
+       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
+                       0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
+               radio->stereo = -1;
+               return -1;
+       }
+       radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
+       return (radio->transfer_buffer)[0];
+}
+
+/* return the device status.  This is, in effect, just whether it
+sees a stereo signal or not.  Pity. */
+static void dsbr100_getstat(dsbr100_device *radio)
+{
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+               USB_REQ_GET_STATUS,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
+               radio->stereo = -1;
+       else
+               radio->stereo = ! (radio->transfer_buffer[0]&0x01);
+}
+
+
+/* USB subsystem interface begins here */
+
+/* check if the device is present and register with v4l and
+usb if it is */
+static int usb_dsbr100_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       dsbr100_device *radio;
+
+       if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
+               return -ENOMEM;
+       if (!(radio->videodev = video_device_alloc())) {
+               kfree(radio);
+               return -ENOMEM;
+       }
+       memcpy(radio->videodev, &dsbr100_videodev_template,
+               sizeof(dsbr100_videodev_template));
+       radio->removed = 0;
+       radio->users = 0;
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->curfreq = FREQ_MIN*FREQ_MUL;
+       video_set_drvdata(radio->videodev, radio);
+       if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
+               radio_nr)) {
+               warn("Could not register video device");
+               video_device_release(radio->videodev);
+               kfree(radio);
+               return -EIO;
+       }
+       usb_set_intfdata(intf, radio);
+       return 0;
+}
+
+/* handle unplugging of the device, release data structures
+if nothing keeps us from doing it.  If something is still
+keeping us busy, the release callback of v4l will take care
+of releasing it.  stv680.c does not relase its private
+data, so I don't do this here either.  Checking out the
+code I'd expect I better did that, but if there's a memory
+leak here it's tiny (~50 bytes per disconnect) */
+static void usb_dsbr100_disconnect(struct usb_interface *intf)
+{
+       dsbr100_device *radio = usb_get_intfdata(intf);
+
+       usb_set_intfdata (intf, NULL);
+       if (radio) {
+               video_unregister_device(radio->videodev);
+               radio->videodev = NULL;
+               if (radio->users) {
+                       kfree(radio);
+               } else {
+                       radio->removed = 1;
+               }
+       }
+}
+
+
+/* Video for Linux interface */
+
+static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
+                               unsigned int cmd, void *arg)
+{
+       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+       if (!radio)
+               return -EIO;
+
+       switch(cmd) {
+               case VIDIOCGCAP: {
+                       struct video_capability *v = arg;
+
+                       memset(v, 0, sizeof(*v));
+                       v->type = VID_TYPE_TUNER;
+                       v->channels = 1;
+                       v->audios = 1;
+                       strcpy(v->name, "D-Link R-100 USB FM Radio");
+                       return 0;
+               }
+               case VIDIOCGTUNER: {
+                       struct video_tuner *v = arg;
+
+                       dsbr100_getstat(radio);
+                       if(v->tuner)    /* Only 1 tuner */
+                               return -EINVAL;
+                       v->rangelow = FREQ_MIN*FREQ_MUL;
+                       v->rangehigh = FREQ_MAX*FREQ_MUL;
+                       v->flags = VIDEO_TUNER_LOW;
+                       v->mode = VIDEO_MODE_AUTO;
+                       v->signal = radio->stereo*0x7000;
+                               /* Don't know how to get signal strength */
+                       v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+                       strcpy(v->name, "DSB R-100");
+                       return 0;
+               }
+               case VIDIOCSTUNER: {
+                       struct video_tuner *v = arg;
+
+                       if(v->tuner!=0)
+                               return -EINVAL;
+                       /* Only 1 tuner so no setting needed ! */
+                       return 0;
+               }
+               case VIDIOCGFREQ: {
+                       int *freq = arg;
+
+                       if (radio->curfreq==-1)
+                               return -EINVAL;
+                       *freq = radio->curfreq;
+                       return 0;
+               }
+               case VIDIOCSFREQ: {
+                       int *freq = arg;
+
+                       radio->curfreq = *freq;
+                       if (dsbr100_setfreq(radio, radio->curfreq)==-1)
+                               warn("Set frequency failed");
+                       return 0;
+               }
+               case VIDIOCGAUDIO: {
+                       struct video_audio *v = arg;
+
+                       memset(v, 0, sizeof(*v));
+                       v->flags |= VIDEO_AUDIO_MUTABLE;
+                       v->mode = VIDEO_SOUND_STEREO;
+                       v->volume = 1;
+                       v->step = 1;
+                       strcpy(v->name, "Radio");
+                       return 0;
+               }
+               case VIDIOCSAUDIO: {
+                       struct video_audio *v = arg;
+
+                       if (v->audio)
+                               return -EINVAL;
+                       if (v->flags&VIDEO_AUDIO_MUTE) {
+                               if (dsbr100_stop(radio)==-1)
+                                       warn("Radio did not respond properly");
+                       }
+                       else
+                               if (dsbr100_start(radio)==-1)
+                                       warn("Radio did not respond properly");
+                       return 0;
+               }
+               default:
+                       return -ENOIOCTLCMD;
+       }
+}
+
+static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
+}
+
+static int usb_dsbr100_open(struct inode *inode, struct file *file)
+{
+       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+       radio->users = 1;
+       if (dsbr100_start(radio)<0) {
+               warn("Radio did not start up properly");
+               radio->users = 0;
+               return -EIO;
+       }
+       dsbr100_setfreq(radio, radio->curfreq);
+       return 0;
+}
+
+static int usb_dsbr100_close(struct inode *inode, struct file *file)
+{
+       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+       if (!radio)
+               return -ENODEV;
+       radio->users = 0;
+       if (radio->removed) {
+               kfree(radio);
+       }
+       return 0;
+}
+
+static int __init dsbr100_init(void)
+{
+       int retval = usb_register(&usb_dsbr100_driver);
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+       return retval;
+}
+
+static void __exit dsbr100_exit(void)
+{
+       usb_deregister(&usb_dsbr100_driver);
+}
+
+module_init (dsbr100_init);
+module_exit (dsbr100_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
index 4e22fc4889e14d3117f8aa2daf00cddf84309e23..f62fd706b45a0b14ceffdff59aa88dc8ec72228a 100644 (file)
 #include <linux/i2c.h>
 #include <linux/usb.h>
 #include <media/tuner.h>
-#include <media/audiochip.h>
+#include <media/msp3400.h>
 #include <media/tveeprom.h>
+#include <media/audiochip.h>
 #include <media/v4l2-common.h>
-#include "msp3400.h"
 
 #include "em28xx.h"
 
@@ -147,11 +147,12 @@ struct em28xx_board em28xx_boards[] = {
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = 0,
-                       .amux     = 6,
+                       .amux     = MSP_INPUT_DEFAULT,
                },{
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = 2,
-                       .amux     = 1,
+                       .amux     = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1,
+                                       MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART),
                }},
        },
        [EM2820_BOARD_MSI_VOX_USB_2] = {
index 780342f7b23965b6891e181fd531d06d33154613..dfba33d0fa617ec41f3a8cf902e2af06d9421dac 100644 (file)
@@ -38,6 +38,7 @@
 #include "em28xx.h"
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include <media/msp3400.h>
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
                      "Markus Rechberger <mrechberger@gmail.com>, " \
@@ -216,9 +217,14 @@ static void video_mux(struct em28xx *dev, int index)
        em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
 
        if (dev->has_msp34xx) {
+               struct v4l2_routing route;
+
                if (dev->i2s_speed)
                        em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
-               em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
+               route.input = dev->ctl_ainput;
+               route.output = MSP_OUTPUT(MSP_OUT_SCART1_DA);
+               /* Note: this is msp3400 specific */
+               em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
                ainput = EM28XX_AUDIO_SRC_TUNER;
                em28xx_audio_source(dev, ainput);
        } else {
diff --git a/drivers/media/video/et61x251/Makefile b/drivers/media/video/et61x251/Makefile
new file mode 100644 (file)
index 0000000..2ff4db9
--- /dev/null
@@ -0,0 +1,4 @@
+et61x251-objs   := et61x251_core.o et61x251_tas5130d1b.o
+
+obj-$(CONFIG_USB_ET61X251)      += et61x251.o
+
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
new file mode 100644 (file)
index 0000000..2e5ca40
--- /dev/null
@@ -0,0 +1,234 @@
+/***************************************************************************
+ * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ET61X251_H_
+#define _ET61X251_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include "et61x251_sensor.h"
+
+/*****************************************************************************/
+
+#define ET61X251_DEBUG
+#define ET61X251_DEBUG_LEVEL         2
+#define ET61X251_MAX_DEVICES         64
+#define ET61X251_PRESERVE_IMGSCALE   0
+#define ET61X251_FORCE_MUNMAP        0
+#define ET61X251_MAX_FRAMES          32
+#define ET61X251_COMPRESSION_QUALITY 0
+#define ET61X251_URBS                2
+#define ET61X251_ISO_PACKETS         7
+#define ET61X251_ALTERNATE_SETTING   13
+#define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
+#define ET61X251_CTRL_TIMEOUT        100
+#define ET61X251_FRAME_TIMEOUT       2
+
+/*****************************************************************************/
+
+static const struct usb_device_id et61x251_id_table[] = {
+       { USB_DEVICE(0x102c, 0x6151), },
+       { USB_DEVICE(0x102c, 0x6251), },
+       { USB_DEVICE(0x102c, 0x6253), },
+       { USB_DEVICE(0x102c, 0x6254), },
+       { USB_DEVICE(0x102c, 0x6255), },
+       { USB_DEVICE(0x102c, 0x6256), },
+       { USB_DEVICE(0x102c, 0x6257), },
+       { USB_DEVICE(0x102c, 0x6258), },
+       { USB_DEVICE(0x102c, 0x6259), },
+       { USB_DEVICE(0x102c, 0x625a), },
+       { USB_DEVICE(0x102c, 0x625b), },
+       { USB_DEVICE(0x102c, 0x625c), },
+       { USB_DEVICE(0x102c, 0x625d), },
+       { USB_DEVICE(0x102c, 0x625e), },
+       { USB_DEVICE(0x102c, 0x625f), },
+       { USB_DEVICE(0x102c, 0x6260), },
+       { USB_DEVICE(0x102c, 0x6261), },
+       { USB_DEVICE(0x102c, 0x6262), },
+       { USB_DEVICE(0x102c, 0x6263), },
+       { USB_DEVICE(0x102c, 0x6264), },
+       { USB_DEVICE(0x102c, 0x6265), },
+       { USB_DEVICE(0x102c, 0x6266), },
+       { USB_DEVICE(0x102c, 0x6267), },
+       { USB_DEVICE(0x102c, 0x6268), },
+       { USB_DEVICE(0x102c, 0x6269), },
+       { }
+};
+
+ET61X251_SENSOR_TABLE
+
+/*****************************************************************************/
+
+enum et61x251_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct et61x251_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum et61x251_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum et61x251_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum et61x251_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum et61x251_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+struct et61x251_sysfs_attr {
+       u8 reg, i2c_reg;
+};
+
+struct et61x251_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DEFINE_MUTEX(et61x251_sysfs_lock);
+static DECLARE_RWSEM(et61x251_disconnect);
+
+struct et61x251_device {
+       struct video_device* v4ldev;
+
+       struct et61x251_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[ET61X251_URBS];
+       void* transfer_buffer[ET61X251_URBS];
+       u8* control_buffer;
+
+       struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum et61x251_io_method io;
+       enum et61x251_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct et61x251_sysfs_attr sysfs;
+       struct et61x251_module_param module_param;
+
+       enum et61x251_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
+{
+       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+               return cam;
+
+       return NULL;
+}
+
+
+void
+et61x251_attach_sensor(struct et61x251_device* cam,
+                      struct et61x251_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ET61X251_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("et61x251: " fmt "\n", ## args);              \
+               else if ((level) == 3)                                        \
+                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+        __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ET61X251_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
new file mode 100644 (file)
index 0000000..dfc9dd7
--- /dev/null
@@ -0,0 +1,2630 @@
+/***************************************************************************
+ * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "et61x251.h"
+
+/*****************************************************************************/
+
+#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
+                               "PC Camera Controllers"
+#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ET61X251_MODULE_LICENSE "GPL"
+#define ET61X251_MODULE_VERSION "1:1.02"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, et61x251_id_table);
+
+MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
+MODULE_VERSION(ET61X251_MODULE_VERSION);
+MODULE_LICENSE(ET61X251_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                "\n -1 = use next available (default)"
+                "\n  n = use minor number n (integer >= 0)"
+                "\nYou can specify up to "
+                __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
+                "\nFor example:"
+                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                "\nthe second registered camera and use auto for the first"
+                "\none and for every other camera."
+                "\n");
+
+static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                              ET61X251_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                "\n<0|1[,...]> Force the application to unmap previously"
+                "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                "\nthis feature. This parameter is specific for each"
+                "\ndetected camera."
+                "\n 0 = do not force memory unmapping"
+                "\n 1 = force memory unmapping (save memory)"
+                "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                "\n");
+
+static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                                      ET61X251_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                "\n<n[,...]> Timeout for a video frame in seconds."
+                "\nThis parameter is specific for each detected camera."
+                "\nDefault value is "
+                __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
+                "\n");
+
+#ifdef ET61X251_DEBUG
+static unsigned short debug = ET61X251_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                "\n<n> Debugging information level, from 0 to 3:"
+                "\n0 = none (use carefully)"
+                "\n1 = critical errors"
+                "\n2 = significant informations"
+                "\n3 = more verbose messages"
+                "\nLevel 3 is useful for testing only, when only "
+                "one device is used."
+                "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
+                "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+et61x251_request_buffers(struct et61x251_device* cam, u32 count,
+                        enum et61x251_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > ET61X251_MAX_FRAMES)
+               count = ET61X251_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void et61x251_release_buffers(struct et61x251_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void et61x251_empty_framequeues(struct et61x251_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void et61x251_requeue_outqueue(struct et61x251_device* cam)
+{
+       struct et61x251_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void et61x251_queue_unusedframes(struct et61x251_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       *buff = value;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (value 0x%02X, index "
+                      "0x%02X, error %d)", value, index, res);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int et61x251_read_reg(struct et61x251_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
+                   index, res);
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+static int
+et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+{
+       int i, r;
+
+       for (i = 1; i <= 8; i++) {
+               if (sensor->interface == ET61X251_I2C_3WIRES) {
+                       r = et61x251_read_reg(cam, 0x8e);
+                       if (!(r & 0x02) && (r >= 0))
+                               return 0;
+               } else {
+                       r = et61x251_read_reg(cam, 0x8b);
+                       if (!(r & 0x01) && (r >= 0))
+                               return 0;
+               }
+               if (r < 0)
+                       return -EIO;
+               udelay(8*8); /* minimum for sensors at 400kHz */
+       }
+
+       return -EBUSY;
+}
+
+
+int
+et61x251_i2c_try_read(struct et61x251_device* cam,
+                     struct et61x251_sensor* sensor, u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x10;
+       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+
+       return err ? -1 : (int)data[0];
+}
+
+
+int
+et61x251_i2c_try_write(struct et61x251_device* cam,
+                      struct et61x251_sensor* sensor, u8 address, u8 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x12;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = value;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       if (err)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+
+       return err ? -1 : 0;
+}
+
+
+int
+et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
+                      u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
+                      u8 data8, u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = data2;
+       data[1] = data3;
+       data[2] = data4;
+       data[3] = data5;
+       data[4] = data6;
+       data[5] = data7;
+       data[6] = data8;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x02 | (n << 4);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       /* Start writing through the serial interface */
+       data[0] = data1;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, &cam->sensor);
+
+       if (err)
+               DBG(3, "I2C raw write failed for %s image sensor",
+                   cam->sensor.name);
+
+       PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
+             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
+             " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
+             data1, data2, data3, data4, data5, data6, data7, data8);
+
+       return err ? -1 : 0;
+
+}
+
+
+int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
+{
+       return et61x251_i2c_try_read(cam, &cam->sensor, address);
+}
+
+
+int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
+{
+       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
+}
+
+/*****************************************************************************/
+
+static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct et61x251_device* cam = urb->context;
+       struct et61x251_frame_t** f;
+       size_t imagesize;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int len, status;
+               void *pos;
+               u8* b1, * b2, sof;
+               const u8 VOID_BYTES = 6;
+               size_t imglen;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               b1 = pos++;
+               b2 = pos++;
+               sof = ((*b1 & 0x3f) == 63);
+               imglen = ((*b1 & 0xc0) << 2) | *b2;
+
+               PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
+                     len, i, imglen);
+
+               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+                       if (sof) {
+                               (*f)->state = F_GRABBING;
+                               (*f)->buf.bytesused = 0;
+                               do_gettimeofday(&(*f)->buf.timestamp);
+                               pos += 22;
+                               DBG(3, "SOF detected: new video frame");
+                       }
+
+               if ((*f)->state == F_GRABBING) {
+                       if (sof && (*f)->buf.bytesused) {
+                               if (cam->sensor.pix_format.pixelformat ==
+                                                        V4L2_PIX_FMT_ET61X251)
+                                       goto end_of_frame;
+                               else {
+                                       DBG(3, "Not expected SOF detected "
+                                              "after %lu bytes",
+                                          (unsigned long)(*f)->buf.bytesused);
+                                       (*f)->state = F_ERROR;
+                                       continue;
+                               }
+                       }
+
+                       if ((*f)->buf.bytesused + imglen > imagesize) {
+                               DBG(3, "Video frame size exceeded");
+                               (*f)->state = F_ERROR;
+                               continue;
+                       }
+
+                       pos += VOID_BYTES;
+
+                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
+                       (*f)->buf.bytesused += imglen;
+
+                       if ((*f)->buf.bytesused == imagesize) {
+                               u32 b;
+end_of_frame:
+                               b = (*f)->buf.bytesused;
+                               (*f)->state = F_DONE;
+                               (*f)->buf.sequence= ++cam->frame_count;
+                               spin_lock(&cam->queue_lock);
+                               list_move_tail(&(*f)->frame, &cam->outqueue);
+                               if (!list_empty(&cam->inqueue))
+                                       (*f) = list_entry(cam->inqueue.next,
+                                                      struct et61x251_frame_t,
+                                                         frame);
+                               else
+                                       (*f) = NULL;
+                               spin_unlock(&cam->queue_lock);
+                               DBG(3, "Video frame captured: : %lu bytes",
+                                      (unsigned long)(b));
+
+                               if (!(*f))
+                                       goto resubmit_urb;
+
+                               if (sof &&
+                                   cam->sensor.pix_format.pixelformat ==
+                                                        V4L2_PIX_FMT_ET61X251)
+                                       goto start_of_frame;
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int et61x251_start_transfer(struct et61x251_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
+                                              864, 896, 920, 956, 980, 1000,
+                                              1022};
+       const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = ET61X251_ISO_PACKETS;
+               urb->complete = et61x251_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       err = et61x251_write_reg(cam, 0x01, 0x03);
+       err = et61x251_write_reg(cam, 0x00, 0x03);
+       err = et61x251_write_reg(cam, 0x08, 0x03);
+       if (err) {
+               err = -EIO;
+               DBG(1, "I/O hardware error");
+               goto free_urbs;
+       }
+
+       err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int et61x251_stop_transfer(struct et61x251_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = ET61X251_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int et61x251_stream_interrupt(struct et61x251_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    ET61X251_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. To "
+                      "use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
+{
+       char str[5];
+       char* endp;
+       unsigned long val;
+
+       if (len < 4) {
+               strncpy(str, buff, len);
+               str[len+1] = '\0';
+       } else {
+               strncpy(str, buff, 4);
+               str[4] = '\0';
+       }
+
+       val = simple_strtoul(str, &endp, 0);
+
+       *count = 0;
+       if (val <= 0xff)
+               *count = (ssize_t)(endp - str);
+       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
+               *count += 1;
+
+       return (u8)val;
+}
+
+/*
+   NOTE 1: being inside one of the following methods implies that the v4l
+          device exists for sure (see kobjects and reference counters)
+   NOTE 2: buffers are PAGE_SIZE long
+*/
+
+static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.reg);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = et61x251_strtou8(buf, len, &count);
+       if (index > 0x8e || !count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.reg = index;
+
+       DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       value = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = et61x251_write_reg(cam, value, cam->sysfs.reg);
+       if (err) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.i2c_reg = index;
+
+       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       value = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
+       if (err) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.i2c_reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+                        et61x251_show_reg, et61x251_store_reg);
+static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+                        et61x251_show_val, et61x251_store_val);
+static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+                        et61x251_show_i2c_reg, et61x251_store_i2c_reg);
+static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+                        et61x251_show_i2c_val, et61x251_store_i2c_val);
+
+
+static void et61x251_create_sysfs(struct et61x251_device* cam)
+{
+       struct video_device *v4ldev = cam->v4ldev;
+
+       video_device_create_file(v4ldev, &class_device_attr_reg);
+       video_device_create_file(v4ldev, &class_device_attr_val);
+       if (cam->sensor.sysfs_ops) {
+               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+       }
+}
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+/*****************************************************************************/
+
+static int
+et61x251_set_pix_format(struct et61x251_device* cam,
+                       struct v4l2_pix_format* pix)
+{
+       int r, err = 0;
+
+       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
+               err += r;
+       if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
+               err += et61x251_write_reg(cam, r & 0xfd, 0x12);
+       else
+               err += et61x251_write_reg(cam, r | 0x02, 0x12);
+
+       return err ? -EIO : 0;
+}
+
+
+static int
+et61x251_set_compression(struct et61x251_device* cam,
+                        struct v4l2_jpegcompression* compression)
+{
+       int r, err = 0;
+
+       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
+               err += r;
+       if (compression->quality == 0)
+               err += et61x251_write_reg(cam, r & 0xfb, 0x12);
+       else
+               err += et61x251_write_reg(cam, r | 0x04, 0x12);
+
+       return err ? -EIO : 0;
+}
+
+
+static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
+{
+       int r = 0, err = 0;
+
+       r = et61x251_read_reg(cam, 0x12);
+       if (r < 0)
+               err += r;
+
+       if (scale == 1)
+               err += et61x251_write_reg(cam, r & ~0x01, 0x12);
+       else if (scale == 2)
+               err += et61x251_write_reg(cam, r | 0x01, 0x12);
+
+       if (err)
+               return -EIO;
+
+       PDBGG("Scaling factor: %u", scale);
+
+       return 0;
+}
+
+
+static int
+et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
+                          s->active_pixel.left),
+           fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
+                          s->active_pixel.top),
+           fmw_length = (u16)(rect->width),
+           fmw_height = (u16)(rect->height);
+       int err = 0;
+
+       err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
+       err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
+       err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
+       err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
+       err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
+                                      | ((fmw_length & 0x300) >> 4)
+                                      | ((fmw_height & 0x300) >> 2), 0x6d);
+       if (err)
+               return -EIO;
+
+       PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
+             fmw_sx, fmw_sy, fmw_length, fmw_height);
+
+       return 0;
+}
+
+
+static int et61x251_init(struct et61x251_device* cam)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+               cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
+       err += et61x251_set_crop(cam, rect);
+       if (err)
+               return err;
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       err += et61x251_set_compression(cam, &cam->compression);
+       err += et61x251_set_pix_format(cam, &s->pix_format);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, &s->pix_format);
+       if (err)
+               return err;
+
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
+               DBG(3, "Compressed video format is active, quality %d",
+                   cam->compression.quality);
+       else
+               DBG(3, "Uncompressed video format is active");
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void et61x251_release_resources(struct et61x251_device* cam)
+{
+       mutex_lock(&et61x251_sysfs_lock);
+
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+
+       usb_put_dev(cam->usbdev);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int et61x251_open(struct inode* inode, struct file* filp)
+{
+       struct et61x251_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&et61x251_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&et61x251_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&et61x251_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&et61x251_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = et61x251_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = et61x251_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       et61x251_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&et61x251_disconnect);
+       return err;
+}
+
+
+static int et61x251_release(struct inode* inode, struct file* filp)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       et61x251_stop_transfer(cam);
+
+       et61x251_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               et61x251_release_resources(cam);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+et61x251_read(struct file* filp, char __user * buf,
+             size_t count, loff_t* f_pos)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose the read "
+                      "method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
+                                             IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       et61x251_empty_framequeues(cam);
+               et61x251_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       et61x251_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err ? err : count;
+}
+
+
+static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
+                                             IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               et61x251_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void et61x251_vm_open(struct vm_area_struct* vma)
+{
+       struct et61x251_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void et61x251_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct et61x251_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct et61x251_vm_ops = {
+       .open = et61x251_vm_open,
+       .close = et61x251_vm_close,
+};
+
+
+static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &et61x251_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       et61x251_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "et61x251",
+               .version = ET61X251_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_pix_format* pix_format = &(s->pix_format);
+       u8 scale;
+       const enum et61x251_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       /* Preserve R,G or B origin */
+       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+       if (rect->width < 4)
+               rect->width = 4;
+       if (rect->height < 4)
+               rect->height = 4;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+
+       rect->width &= ~3L;
+       rect->height &= ~3L;
+
+       if (ET61X251_PRESERVE_IMGSCALE) {
+               /* Calculate the actual scaling factor */
+               u32 a, b;
+               a = rect->width * rect->height;
+               b = pix_format->width * pix_format->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       } else
+               scale = 1;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               et61x251_release_buffers(cam);
+
+       err = et61x251_set_crop(cam, rect);
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+       err += et61x251_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width/scale;
+       s->pix_format.height = rect->height/scale;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               et61x251_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               et61x251_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+       } else if (fmtd.index == 1) {
+               strcpy(fmtd.description, "compressed");
+               fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
+                         void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       u8 scale;
+       const enum et61x251_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       { /* calculate the actual scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       }
+
+       rect.width = scale * pix->width;
+       rect.height = scale * pix->height;
+
+       if (rect.width < 4)
+               rect.width = 4;
+       if (rect.height < 4)
+               rect.height = 4;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+
+       rect.width &= ~3L;
+       rect.height &= ~3L;
+
+       { /* adjust the scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       }
+
+       pix->width = rect.width / scale;
+       pix->height = rect.height / scale;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
+           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+               pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
+                           ? 0 : (pix->width * pix->priv) / 8;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               et61x251_release_buffers(cam);
+
+       err += et61x251_set_pix_format(cam, pix);
+       err += et61x251_set_crop(cam, &rect);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, pix);
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+       err += et61x251_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               et61x251_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               et61x251_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression,
+                        sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum et61x251_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0 && jc.quality != 1)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       err += et61x251_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. "
+                              "Previous buffers are still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       et61x251_empty_framequeues(cam);
+
+       et61x251_release_buffers(cam);
+       if (rb.count)
+               rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               et61x251_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
+                     void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct et61x251_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       et61x251_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
+               sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
+                              unsigned int cmd, void __user * arg)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return et61x251_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return et61x251_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return et61x251_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return et61x251_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return et61x251_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return et61x251_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return et61x251_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return et61x251_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return et61x251_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return et61x251_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return et61x251_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return et61x251_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return et61x251_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return et61x251_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return et61x251_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return et61x251_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return et61x251_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return et61x251_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return et61x251_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return et61x251_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return et61x251_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return et61x251_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int et61x251_ioctl(struct inode* inode, struct file* filp,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "et61x251", cmd);
+
+       err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+
+static struct file_operations et61x251_fops = {
+       .owner = THIS_MODULE,
+       .open =    et61x251_open,
+       .release = et61x251_release,
+       .ioctl =   et61x251_ioctl,
+       .read =    et61x251_read,
+       .poll =    et61x251_poll,
+       .mmap =    et61x251_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+/* It exists a single interface only. We do not need to validate anything. */
+static int
+et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct et61x251_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0;
+
+       if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       DBG(2, "ET61X[12]51 PC Camera Controller detected "
+              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+       for  (i = 0; et61x251_sensor_table[i]; i++) {
+               err = et61x251_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err)
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+       else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (et61x251_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &et61x251_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       et61x251_create_sysfs(cam);
+       DBG(2, "Optional device control through 'sysfs' interface ready");
+#endif
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void et61x251_usb_disconnect(struct usb_interface* intf)
+{
+       struct et61x251_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&et61x251_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               et61x251_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               et61x251_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&et61x251_disconnect);
+}
+
+
+static struct usb_driver et61x251_usb_driver = {
+       .name =       "et61x251",
+       .id_table =   et61x251_id_table,
+       .probe =      et61x251_usb_probe,
+       .disconnect = et61x251_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init et61x251_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION);
+       KDBG(3, ET61X251_MODULE_AUTHOR);
+
+       if ((err = usb_register(&et61x251_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit et61x251_module_exit(void)
+{
+       usb_deregister(&et61x251_usb_driver);
+}
+
+
+module_init(et61x251_module_init);
+module_exit(et61x251_module_exit);
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
new file mode 100644 (file)
index 0000000..65edd08
--- /dev/null
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ET61X251_SENSOR_H_
+#define _ET61X251_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct et61x251_device;
+struct et61x251_sensor;
+
+/*****************************************************************************/
+
+extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
+
+#define ET61X251_SENSOR_TABLE                                                 \
+/* Weak detections must go at the end of the list */                          \
+static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
+       &et61x251_probe_tas5130d1b,                                           \
+       NULL,                                                                 \
+};
+
+extern struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
+
+extern void
+et61x251_attach_sensor(struct et61x251_device* cam,
+                      struct et61x251_sensor* sensor);
+
+/*****************************************************************************/
+
+extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
+extern int et61x251_read_reg(struct et61x251_device*, u16 index);
+extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
+extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
+extern int et61x251_i2c_try_write(struct et61x251_device*,
+                                 struct et61x251_sensor*, u8 address,
+                                 u8 value);
+extern int et61x251_i2c_try_read(struct et61x251_device*,
+                                struct et61x251_sensor*, u8 address);
+extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
+                                 u8 data2, u8 data3, u8 data4, u8 data5,
+                                 u8 data6, u8 data7, u8 data8, u8 address);
+
+/*****************************************************************************/
+
+enum et61x251_i2c_sysfs_ops {
+       ET61X251_I2C_READ = 0x01,
+       ET61X251_I2C_WRITE = 0x02,
+};
+
+enum et61x251_i2c_interface {
+       ET61X251_I2C_2WIRES,
+       ET61X251_I2C_3WIRES,
+};
+
+/* Repeat start condition when RSTA is high */
+enum et61x251_i2c_rsta {
+       ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
+       ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
+};
+
+#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+
+struct et61x251_sensor {
+       char name[32];
+
+       enum et61x251_i2c_sysfs_ops sysfs_ops;
+
+       enum et61x251_i2c_interface interface;
+       u8 i2c_slave_id;
+       enum et61x251_i2c_rsta rsta;
+       struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
+
+       struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
+       struct v4l2_cropcap cropcap;
+       struct v4l2_pix_format pix_format;
+
+       int (*init)(struct et61x251_device* cam);
+       int (*get_ctrl)(struct et61x251_device* cam,
+                       struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct et61x251_device* cam,
+                       const struct v4l2_control* ctrl);
+       int (*set_crop)(struct et61x251_device* cam,
+                       const struct v4l2_rect* rect);
+       int (*set_pix_format)(struct et61x251_device* cam,
+                             const struct v4l2_pix_format* pix);
+
+       /* Private */
+       struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
new file mode 100644 (file)
index 0000000..a7d65b8
--- /dev/null
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
+ * PC Camera Controllers                                                   *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "et61x251_sensor.h"
+
+
+static int tas5130d1b_init(struct et61x251_device* cam)
+{
+       int err = 0;
+
+       err += et61x251_write_reg(cam, 0x14, 0x01);
+       err += et61x251_write_reg(cam, 0x1b, 0x02);
+       err += et61x251_write_reg(cam, 0x02, 0x12);
+       err += et61x251_write_reg(cam, 0x0e, 0x60);
+       err += et61x251_write_reg(cam, 0x80, 0x61);
+       err += et61x251_write_reg(cam, 0xf0, 0x62);
+       err += et61x251_write_reg(cam, 0x03, 0x63);
+       err += et61x251_write_reg(cam, 0x14, 0x64);
+       err += et61x251_write_reg(cam, 0xf4, 0x65);
+       err += et61x251_write_reg(cam, 0x01, 0x66);
+       err += et61x251_write_reg(cam, 0x05, 0x67);
+       err += et61x251_write_reg(cam, 0x8f, 0x68);
+       err += et61x251_write_reg(cam, 0x0f, 0x8d);
+       err += et61x251_write_reg(cam, 0x08, 0x8e);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += et61x251_i2c_raw_write(cam, 2, 0x20,
+                                             0xf6-ctrl->value, 0, 0, 0,
+                                             0, 0, 0, 0);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err += et61x251_i2c_raw_write(cam, 2, 0x40,
+                                             0x47-ctrl->value, 0, 0, 0,
+                                             0, 0, 0, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static struct et61x251_sensor tas5130d1b = {
+       .name = "TAS5130D1B",
+       .interface = ET61X251_I2C_3WIRES,
+       .rsta = ET61X251_I2C_RSTA_STOP,
+       .active_pixel = {
+               .left = 106,
+               .top = 13,
+       },
+       .init = &tas5130d1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x02,
+                       .default_value = 0x0d,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x47,
+                       .step = 0x01,
+                       .default_value = 0x23,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5130d1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+};
+
+
+int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
+{
+       const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x102c, 0x6251), },
+               { }
+       };
+
+       /* Sensor detection is based on USB pid/vid */
+       if (!et61x251_match_id(cam, tas5130d1b_id_table))
+               return -ENODEV;
+
+       et61x251_attach_sensor(cam, &tas5130d1b);
+
+       return 0;
+}
diff --git a/drivers/media/video/font.h b/drivers/media/video/font.h
new file mode 100644 (file)
index 0000000..8b1fecc
--- /dev/null
@@ -0,0 +1,407 @@
+static unsigned char rom8x16_bits[] = {
+/* Character 0 (0x30):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   | *****  |
+   |**   ** |
+   |**   ** |
+   |**  *** |
+   |** **** |
+   |**** ** |
+   |***  ** |
+   |**   ** |
+   |**   ** |
+   | *****  |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xce,
+0xde,
+0xf6,
+0xe6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 1 (0x31):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   |   **   |
+   | ****   |
+   |   **   |
+   |   **   |
+   |   **   |
+   |   **   |
+   |   **   |
+   |   **   |
+   |   **   |
+   | ****** |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x18,
+0x78,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 2 (0x32):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   | *****  |
+   |**   ** |
+   |**   ** |
+   |     ** |
+   |    **  |
+   |   **   |
+   |  **    |
+   | **     |
+   |**   ** |
+   |******* |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc6,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 3 (0x33):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   | *****  |
+   |**   ** |
+   |     ** |
+   |     ** |
+   |  ****  |
+   |     ** |
+   |     ** |
+   |     ** |
+   |**   ** |
+   | *****  |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0x06,
+0x06,
+0x3c,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 4 (0x34):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   |    **  |
+   |   ***  |
+   |  ****  |
+   | ** **  |
+   |**  **  |
+   |**  **  |
+   |******* |
+   |    **  |
+   |    **  |
+   |   **** |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x0c,
+0x1c,
+0x3c,
+0x6c,
+0xcc,
+0xcc,
+0xfe,
+0x0c,
+0x0c,
+0x1e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 5 (0x35):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   |******* |
+   |**      |
+   |**      |
+   |**      |
+   |******  |
+   |     ** |
+   |     ** |
+   |     ** |
+   |**   ** |
+   | *****  |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc0,
+0xc0,
+0xc0,
+0xfc,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 6 (0x36):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   | *****  |
+   |**   ** |
+   |**      |
+   |**      |
+   |******  |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   | *****  |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xfc,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 7 (0x37):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   |******* |
+   |**   ** |
+   |     ** |
+   |    **  |
+   |   **   |
+   |  **    |
+   |  **    |
+   |  **    |
+   |  **    |
+   |  **    |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 8 (0x38):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   | *****  |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   | *****  |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   | *****  |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 9 (0x39):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   | *****  |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   |**   ** |
+   | ****** |
+   |     ** |
+   |     ** |
+   |**   ** |
+   | *****  |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7e,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+/* Character : (0x3a):
+   ht=16, width=8
+   +--------+
+   |        |
+   |        |
+   |        |
+   |        |
+   |        |
+   |    **  |
+   |    **  |
+   |        |
+   |        |
+   |    **  |
+   |    **  |
+   |        |
+   |        |
+   |        |
+   |        |
+   |        |
+   +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+};
index 11ea9765769c7df12e8181040502d4339e295fc8..c40e8ba9a2ea898bf9463879dff07e8818caddae 100644 (file)
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
-#include <media/audiochip.h>
+#include <media/tvaudio.h>
+#include <media/msp3400.h>
 #include <linux/kthread.h>
 #include <linux/suspend.h>
-#include "msp3400.h"
+#include "msp3400-driver.h"
 
 /* ---------------------------------------------------------------------- */
 
@@ -245,31 +246,31 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val)
  * ----------------------------------------------------------------------- */
 
 static int scarts[3][9] = {
-       /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+       /* MASK   IN1     IN2     IN3     IN4     IN1_DA  IN2_DA  MONO    MUTE   */
        /* SCART DSP Input select */
-       { 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+       { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1,     -1,     0x0100, 0x0320 },
        /* SCART1 Output select */
-       { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+       { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
        /* SCART2 Output select */
-       { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+       { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
 };
 
 static char *scart_names[] = {
-       "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+       "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
 };
 
 void msp_set_scart(struct i2c_client *client, int in, int out)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
-       state->in_scart=in;
+       state->in_scart = in;
 
-       if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
-               if (-1 == scarts[out][in])
+       if (in >= 0 && in <= 7 && out >= 0 && out <= 2) {
+               if (-1 == scarts[out][in + 1])
                        return;
 
-               state->acb &= ~scarts[out][SCART_MASK];
-               state->acb |=  scarts[out][in];
+               state->acb &= ~scarts[out][0];
+               state->acb |=  scarts[out][in + 1];
        } else
                state->acb = 0xf60; /* Mute Input and SCART 1 Output */
 
@@ -336,37 +337,6 @@ void msp_set_audio(struct i2c_client *client)
        msp_write_dsp(client, 0x0033, loudness);
 }
 
-int msp_modus(struct i2c_client *client)
-{
-       struct msp_state *state = i2c_get_clientdata(client);
-
-       if (state->radio) {
-               v4l_dbg(1, msp_debug, client, "video mode selected to Radio\n");
-               return 0x0003;
-       }
-
-       if (state->v4l2_std & V4L2_STD_PAL) {
-               v4l_dbg(1, msp_debug, client, "video mode selected to PAL\n");
-
-#if 1
-               /* experimental: not sure this works with all chip versions */
-               return 0x7003;
-#else
-               /* previous value, try this if it breaks ... */
-               return 0x1003;
-#endif
-       }
-       if (state->v4l2_std & V4L2_STD_NTSC) {
-               v4l_dbg(1, msp_debug, client, "video mode selected to NTSC\n");
-               return 0x2003;
-       }
-       if (state->v4l2_std & V4L2_STD_SECAM) {
-               v4l_dbg(1, msp_debug, client, "video mode selected to SECAM\n");
-               return 0x0003;
-       }
-       return 0x0003;
-}
-
 /* ------------------------------------------------------------------------ */
 
 
@@ -585,51 +555,11 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct msp_state *state = i2c_get_clientdata(client);
-       u16 *sarg = arg;
-       int scart = 0;
 
        if (msp_debug >= 2)
                v4l_i2c_print_ioctl(client, cmd);
 
        switch (cmd) {
-       case AUDC_SET_INPUT:
-               if (*sarg == state->input)
-                       break;
-               state->input = *sarg;
-               switch (*sarg) {
-               case AUDIO_RADIO:
-                       /* Hauppauge uses IN2 for the radio */
-                       state->mode = MSP_MODE_FM_RADIO;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_EXTERN_1:
-                       /* IN1 is often used for external input ... */
-                       state->mode = MSP_MODE_EXTERN;
-                       scart       = SCART_IN1;
-                       break;
-               case AUDIO_EXTERN_2:
-                       /* ... sometimes it is IN2 through ;) */
-                       state->mode = MSP_MODE_EXTERN;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_TUNER:
-                       state->mode = -1;
-                       break;
-               default:
-                       if (*sarg & AUDIO_MUTE)
-                               msp_set_scart(client, SCART_MUTE, 0);
-                       break;
-               }
-               if (scart) {
-                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp_set_scart(client, scart, 0);
-                       msp_write_dsp(client, 0x000d, 0x1900);
-                       if (state->opmode != OPMODE_AUTOSELECT)
-                               msp_set_audmode(client);
-               }
-               msp_wake_thread(client);
-               break;
-
        case AUDC_SET_RADIO:
                if (state->radio)
                        return 0;
@@ -692,6 +622,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
                if (va->mode != 0 && state->radio == 0) {
                        state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
+                       msp_set_audmode(client);
                }
                break;
        }
@@ -728,15 +659,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                break;
        }
 
-       /* msp34xx specific */
-       case MSP_SET_MATRIX:
-       {
-               struct msp_matrix *mspm = arg;
-
-               msp_set_scart(client, mspm->input, mspm->output);
-               break;
-       }
-
        /* --- v4l2 ioctls --- */
        case VIDIOC_S_STD:
        {
@@ -750,90 +672,34 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                return 0;
        }
 
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *i = arg;
-
-               if (i->index != 0)
-                       return -EINVAL;
-
-               i->type = V4L2_INPUT_TYPE_TUNER;
-               switch (i->index) {
-               case AUDIO_RADIO:
-                       strcpy(i->name, "Radio");
-                       break;
-               case AUDIO_EXTERN_1:
-                       strcpy(i->name, "Extern 1");
-                       break;
-               case AUDIO_EXTERN_2:
-                       strcpy(i->name, "Extern 2");
-                       break;
-               case AUDIO_TUNER:
-                       strcpy(i->name, "Television");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       }
-
-       case VIDIOC_G_AUDIO:
+       case VIDIOC_INT_G_AUDIO_ROUTING:
        {
-               struct v4l2_audio *a = arg;
+               struct v4l2_routing *rt = arg;
 
-               memset(a, 0, sizeof(*a));
-
-               switch (a->index) {
-               case AUDIO_RADIO:
-                       strcpy(a->name, "Radio");
-                       break;
-               case AUDIO_EXTERN_1:
-                       strcpy(a->name, "Extern 1");
-                       break;
-               case AUDIO_EXTERN_2:
-                       strcpy(a->name, "Extern 2");
-                       break;
-               case AUDIO_TUNER:
-                       strcpy(a->name, "Television");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               a->capability = V4L2_AUDCAP_STEREO;
-               a->mode = 0;  /* TODO: add support for AVL */
+               *rt = state->routing;
                break;
        }
 
-       case VIDIOC_S_AUDIO:
+       case VIDIOC_INT_S_AUDIO_ROUTING:
        {
-               struct v4l2_audio *sarg = arg;
-
-               switch (sarg->index) {
-               case AUDIO_RADIO:
-                       /* Hauppauge uses IN2 for the radio */
-                       state->mode = MSP_MODE_FM_RADIO;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_EXTERN_1:
-                       /* IN1 is often used for external input ... */
-                       state->mode = MSP_MODE_EXTERN;
-                       scart       = SCART_IN1;
-                       break;
-               case AUDIO_EXTERN_2:
-                       /* ... sometimes it is IN2 through ;) */
-                       state->mode = MSP_MODE_EXTERN;
-                       scart       = SCART_IN2;
-                       break;
-               case AUDIO_TUNER:
-                       state->mode = -1;
-                       break;
-               }
-               if (scart) {
-                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       msp_set_scart(client, scart, 0);
-                       msp_write_dsp(client, 0x000d, 0x1900);
+               struct v4l2_routing *rt = arg;
+               int tuner = (rt->input >> 3) & 1;
+               int sc_in = rt->input & 0x7;
+               int sc1_out = rt->output & 0xf;
+               int sc2_out = (rt->output >> 4) & 0xf;
+               u16 val;
+
+               state->routing = *rt;
+               if (state->opmode == OPMODE_AUTOSELECT) {
+                       val = msp_read_dem(client, 0x30) & ~0x100;
+                       msp_write_dem(client, 0x30, val | (tuner ? 0x100 : 0));
+               } else {
+                       val = msp_read_dem(client, 0xbb) & ~0x100;
+                       msp_write_dem(client, 0xbb, val | (tuner ? 0x100 : 0));
                }
+               msp_set_scart(client, sc_in, 0);
+               msp_set_scart(client, sc1_out, 1);
+               msp_set_scart(client, sc2_out, 2);
                msp_set_audmode(client);
                msp_wake_thread(client);
                break;
@@ -866,42 +732,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                break;
        }
 
-       case VIDIOC_G_AUDOUT:
-       {
-               struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
-               int idx = a->index;
-
-               memset(a, 0, sizeof(*a));
-
-               switch (idx) {
-               case 0:
-                       strcpy(a->name, "Scart1 Out");
-                       break;
-               case 1:
-                       strcpy(a->name, "Scart2 Out");
-                       break;
-               case 2:
-                       strcpy(a->name, "I2S Out");
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       }
-
-       case VIDIOC_S_AUDOUT:
-       {
-               struct v4l2_audioout *a = (struct v4l2_audioout *)arg;
-
-               if (a->index < 0 || a->index > 2)
-                       return -EINVAL;
-
-               v4l_dbg(1, msp_debug, client, "Setting audio out on msp34xx to input %i\n", a->index);
-               msp_set_scart(client, state->in_scart, a->index + 1);
-
-               break;
-       }
-
        case VIDIOC_INT_I2S_CLOCK_FREQ:
        {
                u32 *a = (u32 *)arg;
@@ -979,12 +809,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
                                (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
                } else {
-                       v4l_info(client, "Mode:     %s\n", p);
+                       if (state->opmode == OPMODE_AUTODETECT)
+                               v4l_info(client, "Mode:     %s\n", p);
                        v4l_info(client, "Standard: %s (%s%s)\n",
                                msp_standard_std_name(state->std),
                                (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
                                (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
                }
+               v4l_info(client, "Audmode:  0x%04x\n", state->audmode);
+               v4l_info(client, "Routing:  0x%08x (input) 0x%08x (output)\n",
+                               state->routing.input, state->routing.output);
                v4l_info(client, "ACB:      0x%04x\n", state->acb);
                break;
        }
@@ -1063,6 +897,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
        state->muted = 0;
        state->i2s_mode = 0;
        init_waitqueue_head(&state->wq);
+       /* These are the reset input/output positions */
+       state->routing.input = MSP_INPUT_DEFAULT;
+       state->routing.output = MSP_OUTPUT_DEFAULT;
 
        state->rev1 = msp_read_dsp(client, 0x1e);
        if (state->rev1 != -1)
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
new file mode 100644 (file)
index 0000000..1940748
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ */
+
+#ifndef MSP3400_DRIVER_H
+#define MSP3400_DRIVER_H
+
+#include <media/msp3400.h>
+
+/* ---------------------------------------------------------------------- */
+
+/* This macro is allowed for *constants* only, gcc must calculate it
+   at compile time.  Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
+
+#define MSP_MODE_AM_DETECT   0
+#define MSP_MODE_FM_RADIO    2
+#define MSP_MODE_FM_TERRA    3
+#define MSP_MODE_FM_SAT      4
+#define MSP_MODE_FM_NICAM1   5
+#define MSP_MODE_FM_NICAM2   6
+#define MSP_MODE_AM_NICAM    7
+#define MSP_MODE_BTSC        8
+#define MSP_MODE_EXTERN      9
+
+#define SCART_IN1     0
+#define SCART_IN2     1
+#define SCART_IN3     2
+#define SCART_IN4     3
+#define SCART_IN1_DA  4
+#define SCART_IN2_DA  5
+#define SCART_MONO    6
+#define SCART_MUTE    7
+
+#define SCART_DSP_IN  0
+#define SCART1_OUT    1
+#define SCART2_OUT    2
+
+#define OPMODE_AUTO       -1
+#define OPMODE_MANUAL      0
+#define OPMODE_AUTODETECT  1   /* use autodetect (>= msp3410 only) */
+#define OPMODE_AUTOSELECT  2   /* use autodetect & autoselect (>= msp34xxG)   */
+
+/* module parameters */
+extern int msp_debug;
+extern int msp_once;
+extern int msp_amsound;
+extern int msp_standard;
+extern int msp_dolby;
+extern int msp_stereo_thresh;
+
+struct msp_state {
+       int rev1, rev2;
+       u8 has_nicam;
+       u8 has_radio;
+       u8 has_headphones;
+       u8 has_ntsc_jp_d_k3;
+       u8 has_scart4;
+       u8 has_scart23_in_scart2_out;
+       u8 has_scart2_out_volume;
+       u8 has_i2s_conf;
+       u8 has_subwoofer;
+       u8 has_sound_processing;
+       u8 has_virtual_dolby_surround;
+       u8 has_dolby_pro_logic;
+
+       int radio;
+       int opmode;
+       int std;
+       int mode;
+       v4l2_std_id v4l2_std;
+       int nicam_on;
+       int acb;
+       int in_scart;
+       int i2s_mode;
+       int main, second;       /* sound carrier */
+       int input;
+       struct v4l2_routing routing;
+
+       /* v4l2 */
+       int audmode;
+       int rxsubchans;
+
+       int volume, muted;
+       int balance, loudness;
+       int bass, treble;
+
+       /* thread */
+       struct task_struct   *kthread;
+       wait_queue_head_t    wq;
+       int                  restart:1;
+       int                  watch_stereo:1;
+};
+
+/* msp3400-driver.c */
+int msp_write_dem(struct i2c_client *client, int addr, int val);
+int msp_write_dsp(struct i2c_client *client, int addr, int val);
+int msp_read_dem(struct i2c_client *client, int addr);
+int msp_read_dsp(struct i2c_client *client, int addr);
+int msp_reset(struct i2c_client *client);
+void msp_set_scart(struct i2c_client *client, int in, int out);
+void msp_set_mute(struct i2c_client *client);
+void msp_set_audio(struct i2c_client *client);
+int msp_sleep(struct msp_state *state, int timeout);
+
+/* msp3400-kthreads.c */
+const char *msp_standard_std_name(int std);
+void msp_set_audmode(struct i2c_client *client);
+int msp_detect_stereo(struct i2c_client *client);
+int msp3400c_thread(void *data);
+int msp3410d_thread(void *data);
+int msp34xxg_thread(void *data);
+void msp3400c_set_mode(struct i2c_client *client, int mode);
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
+
+#endif /* MSP3400_DRIVER_H */
index 852ab6a115faf1eb365ec6297497194aee8e709a..c3984ea9ca076bc5176788ebb262aa3316f8d55c 100644 (file)
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
-#include <media/audiochip.h>
+#include <media/msp3400.h>
 #include <linux/kthread.h>
 #include <linux/suspend.h>
-#include "msp3400.h"
+#include "msp3400-driver.h"
 
 /* this one uses the automatic sound standard detection of newer msp34xx
    chip versions */
@@ -45,11 +45,13 @@ static struct {
        { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
        { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
        { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
+       { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74  D/K3 Dual FM-Stereo" },
        { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
        { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
        { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
        { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
        { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
+       { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV3)" },
        { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
        { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
        { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
@@ -185,13 +187,14 @@ void msp3400c_set_mode(struct i2c_client *client, int mode)
 {
        struct msp_state *state = i2c_get_clientdata(client);
        struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
+       int tuner = (state->routing.input >> 3) & 1;
        int i;
 
        v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
        state->mode = mode;
        state->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-       msp_write_dem(client, 0x00bb, data->ad_cv);
+       msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0));
 
        for (i = 5; i >= 0; i--)               /* fir 1 */
                msp_write_dem(client, 0x0001, data->fir1[i]);
@@ -207,21 +210,22 @@ void msp3400c_set_mode(struct i2c_client *client, int mode)
        msp3400c_set_carrier(client, data->cdo1, data->cdo2);
 
        msp_set_source(client, data->dsp_src);
-       msp_write_dsp(client, 0x000e, data->dsp_matrix);
+       /* set prescales */
 
-       if (state->has_nicam) {
-               /* nicam prescale */
-               msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
-       }
+       /* volume prescale for SCART (AM mono input) */
+       msp_write_dsp(client, 0x000d, 0x1900);
+       msp_write_dsp(client, 0x000e, data->dsp_matrix);
+       if (state->has_nicam) /* nicam prescale */
+               msp_write_dsp(client, 0x0010, 0x5a00);
 }
 
 /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
    nor do they support stereo BTSC. */
 static void msp3400c_set_audmode(struct i2c_client *client)
 {
-       static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
+       static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" };
        struct msp_state *state = i2c_get_clientdata(client);
-       char *modestr = (state->audmode >= 0 && state->audmode < 4) ?
+       char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
                strmode[state->audmode] : "unknown";
        int src = 0;    /* channel source: FM/AM, nicam or SCART */
 
@@ -246,6 +250,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
                case V4L2_TUNER_MODE_MONO:
                case V4L2_TUNER_MODE_LANG1:
                case V4L2_TUNER_MODE_LANG2:
+               case V4L2_TUNER_MODE_LANG1_LANG2:
                        msp_write_dsp(client, 0x000e, 0x3000);
                        break;
                }
@@ -257,6 +262,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
                        msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
                        break;
                case V4L2_TUNER_MODE_STEREO:
+               case V4L2_TUNER_MODE_LANG1_LANG2:
                        msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
                        break;
                case V4L2_TUNER_MODE_LANG1:
@@ -271,7 +277,6 @@ static void msp3400c_set_audmode(struct i2c_client *client)
        case MSP_MODE_FM_NICAM2:
        case MSP_MODE_AM_NICAM:
                v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
-               msp3400c_set_carrier(client, state->second, state->main);
                if (state->nicam_on)
                        src = 0x0100;  /* NICAM */
                break;
@@ -293,6 +298,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
        /* switch audio */
        switch (state->audmode) {
        case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1_LANG2:
                src |= 0x0020;
                break;
        case V4L2_TUNER_MODE_MONO:
@@ -427,8 +433,8 @@ static void watch_stereo(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
-       if (msp3400c_detect_stereo(client)) {
-               msp3400c_set_audmode(client);
+       if (msp_detect_stereo(client)) {
+               msp_set_audmode(client);
        }
 
        if (msp_once)
@@ -464,7 +470,7 @@ int msp3400c_thread(void *data)
 
                /* mute */
                msp_set_mute(client);
-               msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ );
+               msp3400c_set_mode(client, MSP_MODE_AM_DETECT);
                val1 = val2 = 0;
                max1 = max2 = -1;
                state->watch_stereo = 0;
@@ -572,8 +578,6 @@ int msp3400c_thread(void *data)
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
                                msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
                                msp3400c_set_carrier(client, state->second, state->main);
-                               /* volume prescale for SCART (AM mono input) */
-                               msp_write_dsp(client, 0x000d, 0x1900);
                                state->watch_stereo = 1;
                        } else if (max2 == 0 && state->has_nicam) {
                                /* D/K NICAM */
@@ -651,7 +655,8 @@ int msp3410d_thread(void *data)
                if (msp_sleep(state,200))
                        goto restart;
 
-               /* start autodetect */
+               /* start autodetect. Note: autodetect is not supported for
+                  NTSC-M and radio, hence we force the standard in those cases. */
                if (state->radio)
                        std = 0x40;
                else
@@ -695,23 +700,19 @@ int msp3410d_thread(void *data)
                        v4l_dbg(1, msp_debug, client, "autodetection failed,"
                                " switching to backup standard: %s (0x%04x)\n",
                                msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
-                       val = 0x0009;
+                       state->std = val = 0x0009;
                        msp_write_dem(client, 0x20, val);
                }
 
-               /* set various prescales */
-               msp_write_dsp(client, 0x0d, 0x1900); /* scart */
-               msp_write_dsp(client, 0x0e, 0x2403); /* FM */
-               msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
-
                /* set stereo */
                switch (val) {
                case 0x0008: /* B/G NICAM */
                case 0x000a: /* I NICAM */
-                       if (val == 0x0008)
-                               state->mode = MSP_MODE_FM_NICAM1;
-                       else
+               case 0x000b: /* D/K NICAM */
+                       if (val == 0x000a)
                                state->mode = MSP_MODE_FM_NICAM2;
+                       else
+                               state->mode = MSP_MODE_FM_NICAM1;
                        /* just turn on stereo */
                        state->rxsubchans = V4L2_TUNER_SUB_STEREO;
                        state->nicam_on = 1;
@@ -739,6 +740,7 @@ int msp3410d_thread(void *data)
                        /* scart routing (this doesn't belong here I think) */
                        msp_set_scart(client,SCART_IN2,0);
                        break;
+               case 0x0002:
                case 0x0003:
                case 0x0004:
                case 0x0005:
@@ -748,12 +750,19 @@ int msp3410d_thread(void *data)
                        break;
                }
 
-               /* unmute, restore misc registers */
-               msp_set_audio(client);
-               msp_write_dsp(client, 0x13, state->acb);
+               /* set various prescales */
+               msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+               msp_write_dsp(client, 0x0e, 0x3000); /* FM */
+               if (state->has_nicam)
+                       msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
+
                if (state->has_i2s_conf)
                        msp_write_dem(client, 0x40, state->i2s_mode);
 
+               /* unmute, restore misc registers */
+               msp_set_audio(client);
+
+               msp_write_dsp(client, 0x13, state->acb);
                msp3400c_set_audmode(client);
 
                /* monitor tv audio mode, the first time don't wait
@@ -772,97 +781,154 @@ int msp3410d_thread(void *data)
 
 /* ----------------------------------------------------------------------- */
 
-/* msp34xxG + (autoselect no-thread)                                       */
-/* this one uses both automatic standard detection and automatic sound     */
-/* select which are available in the newer G versions                      */
-/* struct msp: only norm, acb and source are really used in this mode      */
-
-/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
- * the value for source is the same as bit 15:8 of DSP registers 0x08,
- * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
- *
- * this function replaces msp3400c_set_audmode
+/* msp34xxG + (autoselect no-thread)
+ * this one uses both automatic standard detection and automatic sound
+ * select which are available in the newer G versions
+ * struct msp: only norm, acb and source are really used in this mode
  */
-static void msp34xxg_set_source(struct i2c_client *client, int source)
+
+static int msp34xxg_modus(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
-       /* fix matrix mode to stereo and let the msp choose what
-        * to output according to 'source', as recommended
-        * for MONO (source==0) downmixing set bit[7:0] to 0x30
-        */
-       int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
+       if (state->radio) {
+               v4l_dbg(1, msp_debug, client, "selected radio modus\n");
+               return 0x0001;
+       }
 
-       v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value);
-       msp_set_source(client, value);
-       /*
-        * set identification threshold. Personally, I
-        * I set it to a higher value that the default
-        * of 0x190 to ignore noisy stereo signals.
-        * this needs tuning. (recommended range 0x00a0-0x03c0)
-        * 0x7f0 = forced mono mode
-        */
-       /* a2 threshold for stereo/bilingual */
-       msp_write_dem(client, 0x22, msp_stereo_thresh);
-       state->source = source;
+       if (state->v4l2_std & V4L2_STD_PAL) {
+               v4l_dbg(1, msp_debug, client, "selected PAL modus\n");
+               return 0x7001;
+       }
+       if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
+               v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n");
+               return 0x4001;
+       }
+       if (state->v4l2_std == V4L2_STD_NTSC_M_KR) {
+               v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n");
+               return 0x0001;
+       }
+       if (state->v4l2_std & V4L2_STD_MN) {
+               v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n");
+               return 0x2001;
+       }
+       if (state->v4l2_std & V4L2_STD_SECAM) {
+               v4l_dbg(1, msp_debug, client, "selected SECAM modus\n");
+               return 0x6001;
+       }
+       return 0x0001;
 }
 
-/* (re-)initialize the msp34xxg, according to the current norm in state->norm
- * return 0 if it worked, -1 if it failed
- */
-static int msp34xxg_reset(struct i2c_client *client)
+static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
+ {
+       struct msp_state *state = i2c_get_clientdata(client);
+       int source, matrix;
+
+       switch (state->audmode) {
+       case V4L2_TUNER_MODE_MONO:
+               source = 0; /* mono only */
+               matrix = 0x30;
+               break;
+       case V4L2_TUNER_MODE_LANG1:
+               source = 3; /* stereo or A */
+               matrix = 0x00;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               source = 4; /* stereo or B */
+               matrix = 0x10;
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+       default:
+               source = 1; /* stereo or A|B */
+               matrix = 0x20;
+               break;
+       }
+
+       if (in == MSP_DSP_OUT_TUNER)
+               source = (source << 8) | 0x20;
+       /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
+          instead of 11, 12, 13. So we add one for that msp version. */
+       else if (in >= MSP_DSP_OUT_MAIN_AVC && state->has_dolby_pro_logic)
+               source = ((in + 1) << 8) | matrix;
+       else
+               source = (in << 8) | matrix;
+
+       v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
+                       in, source, reg);
+       msp_write_dsp(client, reg, source);
+}
+
+static void msp34xxg_set_sources(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+       u32 in = state->routing.input;
+
+       msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
+       /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
+       msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf);
+       msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf);
+       msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf);
+       if (state->has_scart23_in_scart2_out)
+               msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf);
+       msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf);
+}
+
+/* (re-)initialize the msp34xxg */
+static void msp34xxg_reset(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
-       int modus, std;
+       int tuner = (state->routing.input >> 3) & 1;
+       int modus;
+
+       /* initialize std to 1 (autodetect) to signal that no standard is
+          selected yet. */
+       state->std = 1;
 
-       if (msp_reset(client))
-               return -1;
+       msp_reset(client);
 
        /* make sure that input/output is muted (paranoid mode) */
        /* ACB, mute DSP input, mute SCART 1 */
-       if (msp_write_dsp(client, 0x13, 0x0f20))
-               return -1;
+       msp_write_dsp(client, 0x13, 0x0f20);
 
        if (state->has_i2s_conf)
                msp_write_dem(client, 0x40, state->i2s_mode);
 
        /* step-by-step initialisation, as described in the manual */
-       modus = msp_modus(client);
-       if (state->radio)
-               std = 0x40;
-       else
-               std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
-       modus &= ~0x03; /* STATUS_CHANGE = 0 */
-       modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION = 1 */
-       if (msp_write_dem(client, 0x30, modus))
-               return -1;
-       if (msp_write_dem(client, 0x20, std))
-               return -1;
+       modus = msp34xxg_modus(client);
+       modus |= tuner ? 0x100 : 0;
+       msp_write_dem(client, 0x30, modus);
 
        /* write the dsps that may have an influence on
           standard/audio autodetection right now */
-       msp34xxg_set_source(client, state->source);
-
-       /* AM/FM Prescale [15:8] 75khz deviation */
-       if (msp_write_dsp(client, 0x0e, 0x3000))
-               return -1;
+       msp34xxg_set_sources(client);
 
-       /* NICAM Prescale 9db gain (as recommended) */
-       if (msp_write_dsp(client, 0x10, 0x5a00))
-               return -1;
+       msp_write_dsp(client, 0x0d, 0x1900); /* scart */
+       msp_write_dsp(client, 0x0e, 0x3000); /* FM */
+       if (state->has_nicam)
+               msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
 
-       return 0;
+       /* set identification threshold. Personally, I
+        * I set it to a higher value than the default
+        * of 0x190 to ignore noisy stereo signals.
+        * this needs tuning. (recommended range 0x00a0-0x03c0)
+        * 0x7f0 = forced mono mode
+        *
+        * a2 threshold for stereo/bilingual.
+        * Note: this register is part of the Manual/Compatibility mode.
+        * It is supported by all 'G'-family chips.
+        */
+       msp_write_dem(client, 0x22, msp_stereo_thresh);
 }
 
 int msp34xxg_thread(void *data)
 {
        struct i2c_client *client = data;
        struct msp_state *state = i2c_get_clientdata(client);
-       int val, std, i;
+       int val, i;
 
        v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
 
-       state->source = 1; /* default */
        for (;;) {
                v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
                msp_sleep(state, -1);
@@ -876,12 +942,14 @@ int msp34xxg_thread(void *data)
 
                /* setup the chip*/
                msp34xxg_reset(client);
-               std = msp_standard;
-               if (std != 0x01)
+               state->std = state->radio ? 0x40 : msp_standard;
+               if (state->std != 1)
                        goto unmute;
+               /* start autodetect */
+               msp_write_dem(client, 0x20, state->std);
 
                /* watch autodetect */
-               v4l_dbg(1, msp_debug, client, "triggered autodetect, waiting for result\n");
+               v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
                for (i = 0; i < 10; i++) {
                        if (msp_sleep(state, 100))
                                goto restart;
@@ -889,20 +957,19 @@ int msp34xxg_thread(void *data)
                        /* check results */
                        val = msp_read_dem(client, 0x7e);
                        if (val < 0x07ff) {
-                               std = val;
+                               state->std = val;
                                break;
                        }
                        v4l_dbg(2, msp_debug, client, "detection still in progress\n");
                }
-               if (std == 1) {
+               if (state->std == 1) {
                        v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
                        continue;
                }
 
        unmute:
-               state->std = std;
-               v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n",
-                       msp_standard_std_name(std), std);
+               v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
+                       msp_standard_std_name(state->std), state->std);
 
                /* unmute: dispatch sound to scart output, set scart volume */
                msp_set_audio(client);
@@ -911,20 +978,33 @@ int msp34xxg_thread(void *data)
                if (msp_write_dsp(client, 0x13, state->acb))
                        return -1;
 
-               if (state->has_i2s_conf)
-                       msp_write_dem(client, 0x40, state->i2s_mode);
+               /* the periodic stereo/SAP check is only relevant for
+                  the 0x20 standard (BTSC) */
+               if (state->std != 0x20)
+                       continue;
+
+               state->watch_stereo = 1;
+
+               /* monitor tv audio mode, the first time don't wait
+                  in order to get a quick stereo/SAP update */
+               watch_stereo(client);
+               while (state->watch_stereo) {
+                       watch_stereo(client);
+                       if (msp_sleep(state, 5000))
+                               goto restart;
+               }
        }
        v4l_dbg(1, msp_debug, client, "thread: exit\n");
        return 0;
 }
 
-static void msp34xxg_detect_stereo(struct i2c_client *client)
+static int msp34xxg_detect_stereo(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
-
        int status = msp_read_dem(client, 0x0200);
        int is_bilingual = status & 0x100;
        int is_stereo = status & 0x40;
+       int oldrx = state->rxsubchans;
 
        state->rxsubchans = 0;
        if (is_stereo)
@@ -932,42 +1012,31 @@ static void msp34xxg_detect_stereo(struct i2c_client *client)
        else
                state->rxsubchans = V4L2_TUNER_SUB_MONO;
        if (is_bilingual) {
-               state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-               /* I'm supposed to check whether it's SAP or not
-                * and set only LANG2/SAP in this case. Yet, the MSP
-                * does a lot of work to hide this and handle everything
-                * the same way. I don't want to work around it so unless
-                * this is a problem, I'll handle SAP just like lang1/lang2.
-                */
+               if (state->std == 0x20)
+                       state->rxsubchans |= V4L2_TUNER_SUB_SAP;
+               else
+                       state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
        }
        v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
                status, is_stereo, is_bilingual, state->rxsubchans);
+       return (oldrx != state->rxsubchans);
 }
 
 static void msp34xxg_set_audmode(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
-       int source;
 
-       switch (state->audmode) {
-       case V4L2_TUNER_MODE_MONO:
-               source = 0; /* mono only */
-               break;
-       case V4L2_TUNER_MODE_STEREO:
-               source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
-               /* problem: that could also mean 2 (scart input) */
-               break;
-       case V4L2_TUNER_MODE_LANG1:
-               source = 3; /* stereo or A */
-               break;
-       case V4L2_TUNER_MODE_LANG2:
-               source = 4; /* stereo or B */
-               break;
-       default:
-               source  = 1;
-               break;
+       if (state->std == 0x20) {
+              if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
+                  (state->audmode == V4L2_TUNER_MODE_STEREO ||
+                   state->audmode == V4L2_TUNER_MODE_LANG2)) {
+                       msp_write_dem(client, 0x20, 0x21);
+              } else {
+                       msp_write_dem(client, 0x20, 0x20);
+              }
        }
-       msp34xxg_set_source(client, source);
+
+       msp34xxg_set_sources(client);
 }
 
 void msp_set_audmode(struct i2c_client *client)
@@ -977,7 +1046,6 @@ void msp_set_audmode(struct i2c_client *client)
        switch (state->opmode) {
        case OPMODE_MANUAL:
        case OPMODE_AUTODETECT:
-               state->watch_stereo = 0;
                msp3400c_set_audmode(client);
                break;
        case OPMODE_AUTOSELECT:
@@ -986,18 +1054,17 @@ void msp_set_audmode(struct i2c_client *client)
        }
 }
 
-void msp_detect_stereo(struct i2c_client *client)
+int msp_detect_stereo(struct i2c_client *client)
 {
        struct msp_state *state  = i2c_get_clientdata(client);
 
        switch (state->opmode) {
        case OPMODE_MANUAL:
        case OPMODE_AUTODETECT:
-               msp3400c_detect_stereo(client);
-               break;
+               return msp3400c_detect_stereo(client);
        case OPMODE_AUTOSELECT:
-               msp34xxg_detect_stereo(client);
-               break;
+               return msp34xxg_detect_stereo(client);
        }
+       return 0;
 }
 
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
deleted file mode 100644 (file)
index 6fb5c8c..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- */
-
-#ifndef MSP3400_H
-#define MSP3400_H
-
-/* ---------------------------------------------------------------------- */
-
-/* This macro is allowed for *constants* only, gcc must calculate it
-   at compile time.  Remember -- no floats in kernel mode */
-#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
-
-#define MSP_MODE_AM_DETECT   0
-#define MSP_MODE_FM_RADIO    2
-#define MSP_MODE_FM_TERRA    3
-#define MSP_MODE_FM_SAT      4
-#define MSP_MODE_FM_NICAM1   5
-#define MSP_MODE_FM_NICAM2   6
-#define MSP_MODE_AM_NICAM    7
-#define MSP_MODE_BTSC        8
-#define MSP_MODE_EXTERN      9
-
-#define SCART_MASK    0
-#define SCART_IN1     1
-#define SCART_IN2     2
-#define SCART_IN1_DA  3
-#define SCART_IN2_DA  4
-#define SCART_IN3     5
-#define SCART_IN4     6
-#define SCART_MONO    7
-#define SCART_MUTE    8
-
-#define SCART_DSP_IN  0
-#define SCART1_OUT    1
-#define SCART2_OUT    2
-
-#define OPMODE_AUTO       -1
-#define OPMODE_MANUAL      0
-#define OPMODE_AUTODETECT  1   /* use autodetect (>= msp3410 only) */
-#define OPMODE_AUTOSELECT  2   /* use autodetect & autoselect (>= msp34xxG)   */
-
-/* module parameters */
-extern int msp_debug;
-extern int msp_once;
-extern int msp_amsound;
-extern int msp_standard;
-extern int msp_dolby;
-extern int msp_stereo_thresh;
-
-struct msp_state {
-       int rev1, rev2;
-       u8 has_nicam;
-       u8 has_radio;
-       u8 has_headphones;
-       u8 has_ntsc_jp_d_k3;
-       u8 has_scart4;
-       u8 has_scart23_in_scart2_out;
-       u8 has_scart2_out_volume;
-       u8 has_i2s_conf;
-       u8 has_subwoofer;
-       u8 has_sound_processing;
-       u8 has_virtual_dolby_surround;
-       u8 has_dolby_pro_logic;
-
-       int radio;
-       int opmode;
-       int std;
-       int mode;
-       v4l2_std_id v4l2_std;
-       int nicam_on;
-       int acb;
-       int in_scart;
-       int i2s_mode;
-       int main, second;       /* sound carrier */
-       int input;
-       int source;             /* see msp34xxg_set_source */
-
-       /* v4l2 */
-       int audmode;
-       int rxsubchans;
-
-       int volume, muted;
-       int balance, loudness;
-       int bass, treble;
-
-       /* thread */
-       struct task_struct   *kthread;
-       wait_queue_head_t    wq;
-       int                  restart:1;
-       int                  watch_stereo:1;
-};
-
-/* msp3400-driver.c */
-int msp_write_dem(struct i2c_client *client, int addr, int val);
-int msp_write_dsp(struct i2c_client *client, int addr, int val);
-int msp_read_dem(struct i2c_client *client, int addr);
-int msp_read_dsp(struct i2c_client *client, int addr);
-int msp_reset(struct i2c_client *client);
-void msp_set_scart(struct i2c_client *client, int in, int out);
-void msp_set_mute(struct i2c_client *client);
-void msp_set_audio(struct i2c_client *client);
-int msp_modus(struct i2c_client *client);
-int msp_sleep(struct msp_state *state, int timeout);
-
-/* msp3400-kthreads.c */
-const char *msp_standard_std_name(int std);
-void msp_set_audmode(struct i2c_client *client);
-void msp_detect_stereo(struct i2c_client *client);
-int msp3400c_thread(void *data);
-int msp3410d_thread(void *data);
-int msp34xxg_thread(void *data);
-void msp3400c_set_mode(struct i2c_client *client, int mode);
-void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
-
-#endif /* MSP3400_H */
index eb3b31867494b0ac0bf97ae08f94c7c84d48ae20..b0aea4002d1124235922f2396553e43f0079092b 100644 (file)
@@ -198,13 +198,13 @@ static int mxb_probe(struct saa7146_dev* dev)
        /* loop through all i2c-devices on the bus and look who is there */
        list_for_each(item,&mxb->i2c_adapter.clients) {
                client = list_entry(item, struct i2c_client, list);
-               if( I2C_TEA6420_1 == client->addr )
+               if( I2C_ADDR_TEA6420_1 == client->addr )
                        mxb->tea6420_1 = client;
-               if( I2C_TEA6420_2 == client->addr )
+               if( I2C_ADDR_TEA6420_2 == client->addr )
                        mxb->tea6420_2 = client;
                if( I2C_TEA6415C_2 == client->addr )
                        mxb->tea6415c = client;
-               if( I2C_TDA9840 == client->addr )
+               if( I2C_ADDR_TDA9840 == client->addr )
                        mxb->tda9840 = client;
                if( I2C_SAA7111 == client->addr )
                        mxb->saa7111a = client;
@@ -790,6 +790,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                                DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
                                break;
                        }
+                       case V4L2_TUNER_MODE_LANG1_LANG2: {
+                               mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
+                               byte = TDA9840_SET_BOTH;
+                               DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
+                               break;
+                       }
                        case V4L2_TUNER_MODE_LANG1: {
                                mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
                                byte = TDA9840_SET_LANG1;
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
new file mode 100644 (file)
index 0000000..fdc8e3f
--- /dev/null
@@ -0,0 +1,5932 @@
+/*
+ * OmniVision OV511 Camera-to-USB Bridge Driver
+ *
+ * Copyright (c) 1999-2003 Mark W. McClelland
+ * Original decompression code Copyright 1998-2000 OmniVision Technologies
+ * Many improvements by Bret Wallach <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
+ * Snapshot code by Kevin Moore
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka <claudio@conectiva.com>
+ * Original SAA7111A code by Dave Perks <dperks@ibm.net>
+ * URB error messages from pwc driver by Nemosoft
+ * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
+ * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
+ *
+ * Based on the Linux CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt.
+ *
+ * Please see the file: Documentation/usb/ov511.txt
+ * and the website at:  http://alpha.dyndns.org/ov511
+ * for more info.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+
+#if defined (__i386__)
+       #include <asm/cpufeature.h>
+#endif
+
+#include "ov511.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.64 for Linux 2.5"
+#define EMAIL "mark@alpha.dyndns.org"
+#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
+       & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
+       <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
+#define DRIVER_DESC "ov511 USB Camera Driver"
+
+#define OV511_I2C_RETRIES 3
+#define ENABLE_Y_QUANTABLE 1
+#define ENABLE_UV_QUANTABLE 1
+
+#define OV511_MAX_UNIT_VIDEO 16
+
+/* Pixel count * bytes per YUV420 pixel (1.5) */
+#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
+
+#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
+
+/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
+#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
+
+#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
+
+/**********************************************************************
+ * Module Parameters
+ * (See ov511.txt for detailed descriptions of these)
+ **********************************************************************/
+
+/* These variables (and all static globals) default to zero */
+static int autobright          = 1;
+static int autogain            = 1;
+static int autoexp             = 1;
+static int debug;
+static int snapshot;
+static int cams                        = 1;
+static int compress;
+static int testpat;
+static int dumppix;
+static int led                         = 1;
+static int dump_bridge;
+static int dump_sensor;
+static int printph;
+static int phy                 = 0x1f;
+static int phuv                        = 0x05;
+static int pvy                 = 0x06;
+static int pvuv                        = 0x06;
+static int qhy                 = 0x14;
+static int qhuv                        = 0x03;
+static int qvy                 = 0x04;
+static int qvuv                        = 0x04;
+static int lightfreq;
+static int bandingfilter;
+static int clockdiv            = -1;
+static int packetsize          = -1;
+static int framedrop           = -1;
+static int fastset;
+static int force_palette;
+static int backlight;
+static int unit_video[OV511_MAX_UNIT_VIDEO];
+static int remove_zeros;
+static int mirror;
+static int ov518_color;
+
+module_param(autobright, int, 0);
+MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
+module_param(autogain, int, 0);
+MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
+module_param(autoexp, int, 0);
+MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug,
+  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
+module_param(snapshot, int, 0);
+MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
+module_param(cams, int, 0);
+MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
+module_param(compress, int, 0);
+MODULE_PARM_DESC(compress, "Turn on compression");
+module_param(testpat, int, 0);
+MODULE_PARM_DESC(testpat,
+  "Replace image with vertical bar testpattern (only partially working)");
+module_param(dumppix, int, 0);
+MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
+module_param(led, int, 0);
+MODULE_PARM_DESC(led,
+  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
+module_param(dump_bridge, int, 0);
+MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
+module_param(dump_sensor, int, 0);
+MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
+module_param(printph, int, 0);
+MODULE_PARM_DESC(printph, "Print frame start/end headers");
+module_param(phy, int, 0);
+MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
+module_param(phuv, int, 0);
+MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
+module_param(pvy, int, 0);
+MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
+module_param(pvuv, int, 0);
+MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
+module_param(qhy, int, 0);
+MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
+module_param(qhuv, int, 0);
+MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
+module_param(qvy, int, 0);
+MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
+module_param(qvuv, int, 0);
+MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
+module_param(lightfreq, int, 0);
+MODULE_PARM_DESC(lightfreq,
+  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
+module_param(bandingfilter, int, 0);
+MODULE_PARM_DESC(bandingfilter,
+  "Enable banding filter (to reduce effects of fluorescent lighting)");
+module_param(clockdiv, int, 0);
+MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
+module_param(packetsize, int, 0);
+MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
+module_param(framedrop, int, 0);
+MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
+module_param(fastset, int, 0);
+MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
+module_param(force_palette, int, 0);
+MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
+module_param(backlight, int, 0);
+MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
+static int num_uv;
+module_param_array(unit_video, int, &num_uv, 0);
+MODULE_PARM_DESC(unit_video,
+  "Force use of specific minor number(s). 0 is not allowed.");
+module_param(remove_zeros, int, 0);
+MODULE_PARM_DESC(remove_zeros,
+  "Remove zero-padding from uncompressed incoming data");
+module_param(mirror, int, 0);
+MODULE_PARM_DESC(mirror, "Reverse image horizontally");
+module_param(ov518_color, int, 0);
+MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/**********************************************************************
+ * Miscellaneous Globals
+ **********************************************************************/
+
+static struct usb_driver ov511_driver;
+
+/* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+static const int i2c_detect_tries = 5;
+
+static struct usb_device_id device_table [] = {
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
+       { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
+       { }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
+static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
+static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
+static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
+static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
+
+/**********************************************************************
+ * Symbolic Names
+ **********************************************************************/
+
+/* Known OV511-based cameras */
+static struct symbolic_list camlist[] = {
+       {   0, "Generic Camera (no ID)" },
+       {   1, "Mustek WCam 3X" },
+       {   3, "D-Link DSB-C300" },
+       {   4, "Generic OV511/OV7610" },
+       {   5, "Puretek PT-6007" },
+       {   6, "Lifeview USB Life TV (NTSC)" },
+       {  21, "Creative Labs WebCam 3" },
+       {  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
+       {  36, "Koala-Cam" },
+       {  38, "Lifeview USB Life TV (PAL)" },
+       {  41, "Samsung Anycam MPC-M10" },
+       {  43, "Mtekvision Zeca MV402" },
+       {  46, "Suma eON" },
+       {  70, "Lifeview USB Life TV (PAL/SECAM)" },
+       { 100, "Lifeview RoboCam" },
+       { 102, "AverMedia InterCam Elite" },
+       { 112, "MediaForte MV300" },    /* or OV7110 evaluation kit */
+       { 134, "Ezonics EZCam II" },
+       { 192, "Webeye 2000B" },
+       { 253, "Alpha Vision Tech. AlphaCam SE" },
+       {  -1, NULL }
+};
+
+/* Video4Linux1 Palettes */
+static struct symbolic_list v4l1_plist[] = {
+       { VIDEO_PALETTE_GREY,   "GREY" },
+       { VIDEO_PALETTE_HI240,  "HI240" },
+       { VIDEO_PALETTE_RGB565, "RGB565" },
+       { VIDEO_PALETTE_RGB24,  "RGB24" },
+       { VIDEO_PALETTE_RGB32,  "RGB32" },
+       { VIDEO_PALETTE_RGB555, "RGB555" },
+       { VIDEO_PALETTE_YUV422, "YUV422" },
+       { VIDEO_PALETTE_YUYV,   "YUYV" },
+       { VIDEO_PALETTE_UYVY,   "UYVY" },
+       { VIDEO_PALETTE_YUV420, "YUV420" },
+       { VIDEO_PALETTE_YUV411, "YUV411" },
+       { VIDEO_PALETTE_RAW,    "RAW" },
+       { VIDEO_PALETTE_YUV422P,"YUV422P" },
+       { VIDEO_PALETTE_YUV411P,"YUV411P" },
+       { VIDEO_PALETTE_YUV420P,"YUV420P" },
+       { VIDEO_PALETTE_YUV410P,"YUV410P" },
+       { -1, NULL }
+};
+
+static struct symbolic_list brglist[] = {
+       { BRG_OV511,            "OV511" },
+       { BRG_OV511PLUS,        "OV511+" },
+       { BRG_OV518,            "OV518" },
+       { BRG_OV518PLUS,        "OV518+" },
+       { -1, NULL }
+};
+
+static struct symbolic_list senlist[] = {
+       { SEN_OV76BE,   "OV76BE" },
+       { SEN_OV7610,   "OV7610" },
+       { SEN_OV7620,   "OV7620" },
+       { SEN_OV7620AE, "OV7620AE" },
+       { SEN_OV6620,   "OV6620" },
+       { SEN_OV6630,   "OV6630" },
+       { SEN_OV6630AE, "OV6630AE" },
+       { SEN_OV6630AF, "OV6630AF" },
+       { SEN_OV8600,   "OV8600" },
+       { SEN_KS0127,   "KS0127" },
+       { SEN_KS0127B,  "KS0127B" },
+       { SEN_SAA7111A, "SAA7111A" },
+       { -1, NULL }
+};
+
+/* URB error codes: */
+static struct symbolic_list urb_errlist[] = {
+       { -ENOSR,       "Buffer error (overrun)" },
+       { -EPIPE,       "Stalled (device not responding)" },
+       { -EOVERFLOW,   "Babble (bad cable?)" },
+       { -EPROTO,      "Bit-stuff error (bad cable?)" },
+       { -EILSEQ,      "CRC/Timeout" },
+       { -ETIMEDOUT,   "NAK (device does not respond)" },
+       { -1, NULL }
+};
+
+/**********************************************************************
+ * Memory management
+ **********************************************************************/
+static void *
+rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void
+rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+/**********************************************************************
+ *
+ * Register I/O
+ *
+ **********************************************************************/
+
+/* Write an OV51x register */
+static int
+reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
+{
+       int rc;
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       mutex_lock(&ov->cbuf_lock);
+       ov->cbuf[0] = value;
+       rc = usb_control_msg(ov->dev,
+                            usb_sndctrlpipe(ov->dev, 0),
+                            (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
+       mutex_unlock(&ov->cbuf_lock);
+
+       if (rc < 0)
+               err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
+
+       return rc;
+}
+
+/* Read from an OV51x register */
+/* returns: negative is error, pos or zero is data */
+static int
+reg_r(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc;
+
+       mutex_lock(&ov->cbuf_lock);
+       rc = usb_control_msg(ov->dev,
+                            usb_rcvctrlpipe(ov->dev, 0),
+                            (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
+                            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
+
+       if (rc < 0) {
+               err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
+       } else {
+               rc = ov->cbuf[0];
+               PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
+       }
+
+       mutex_unlock(&ov->cbuf_lock);
+
+       return rc;
+}
+
+/*
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int
+reg_w_mask(struct usb_ov511 *ov,
+          unsigned char reg,
+          unsigned char value,
+          unsigned char mask)
+{
+       int ret;
+       unsigned char oldval, newval;
+
+       ret = reg_r(ov, reg);
+       if (ret < 0)
+               return ret;
+
+       oldval = (unsigned char) ret;
+       oldval &= (~mask);              /* Clear the masked bits */
+       value &= mask;                  /* Enforce mask on value */
+       newval = oldval | value;        /* Set the desired bits */
+
+       return (reg_w(ov, reg, newval));
+}
+
+/*
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
+static int
+ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
+{
+       int rc;
+
+       PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
+
+       mutex_lock(&ov->cbuf_lock);
+
+       *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
+
+       rc = usb_control_msg(ov->dev,
+                            usb_sndctrlpipe(ov->dev, 0),
+                            1 /* REG_IO */,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                            0, (__u16)reg, ov->cbuf, n, 1000);
+       mutex_unlock(&ov->cbuf_lock);
+
+       if (rc < 0)
+               err("reg write multiple: error %d: %s", rc,
+                   symbolic(urb_errlist, rc));
+
+       return rc;
+}
+
+static int
+ov511_upload_quan_tables(struct usb_ov511 *ov)
+{
+       unsigned char *pYTable = yQuanTable511;
+       unsigned char *pUVTable = uvQuanTable511;
+       unsigned char val0, val1;
+       int i, rc, reg = R511_COMP_LUT_BEGIN;
+
+       PDEBUG(4, "Uploading quantization tables");
+
+       for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
+               if (ENABLE_Y_QUANTABLE) {
+                       val0 = *pYTable++;
+                       val1 = *pYTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               if (ENABLE_UV_QUANTABLE) {
+                       val0 = *pUVTable++;
+                       val1 = *pUVTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               reg++;
+       }
+
+       return 0;
+}
+
+/* OV518 quantization tables are 8x4 (instead of 8x8) */
+static int
+ov518_upload_quan_tables(struct usb_ov511 *ov)
+{
+       unsigned char *pYTable = yQuanTable518;
+       unsigned char *pUVTable = uvQuanTable518;
+       unsigned char val0, val1;
+       int i, rc, reg = R511_COMP_LUT_BEGIN;
+
+       PDEBUG(4, "Uploading quantization tables");
+
+       for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
+               if (ENABLE_Y_QUANTABLE) {
+                       val0 = *pYTable++;
+                       val1 = *pYTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               if (ENABLE_UV_QUANTABLE) {
+                       val0 = *pUVTable++;
+                       val1 = *pUVTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               reg++;
+       }
+
+       return 0;
+}
+
+static int
+ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
+{
+       int rc;
+
+       /* Setting bit 0 not allowed on 518/518Plus */
+       if (ov->bclass == BCL_OV518)
+               reset_type &= 0xfe;
+
+       PDEBUG(4, "Reset: type=0x%02X", reset_type);
+
+       rc = reg_w(ov, R51x_SYS_RESET, reset_type);
+       rc = reg_w(ov, R51x_SYS_RESET, 0);
+
+       if (rc < 0)
+               err("reset: command failed");
+
+       return rc;
+}
+
+/**********************************************************************
+ *
+ * Low-level I2C I/O functions
+ *
+ **********************************************************************/
+
+/* NOTE: Do not call this function directly!
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_w(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int
+ov518_i2c_write_internal(struct usb_ov511 *ov,
+                        unsigned char reg,
+                        unsigned char value)
+{
+       int rc;
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       /* Select camera register */
+       rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Write "value" to I2C data port of OV511 */
+       rc = reg_w(ov, R51x_I2C_DATA, value);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 3-byte write cycle */
+       rc = reg_w(ov, R518_I2C_CTL, 0x01);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+/* NOTE: Do not call this function directly! */
+static int
+ov511_i2c_write_internal(struct usb_ov511 *ov,
+                        unsigned char reg,
+                        unsigned char value)
+{
+       int rc, retries;
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       /* Three byte write cycle */
+       for (retries = OV511_I2C_RETRIES; ; ) {
+               /* Select camera register */
+               rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
+               if (rc < 0)
+                       break;
+
+               /* Write "value" to I2C data port of OV511 */
+               rc = reg_w(ov, R51x_I2C_DATA, value);
+               if (rc < 0)
+                       break;
+
+               /* Initiate 3-byte write cycle */
+               rc = reg_w(ov, R511_I2C_CTL, 0x01);
+               if (rc < 0)
+                       break;
+
+               /* Retry until idle */
+               do
+                       rc = reg_r(ov, R511_I2C_CTL);
+               while (rc > 0 && ((rc&1) == 0));
+               if (rc < 0)
+                       break;
+
+               /* Ack? */
+               if ((rc&2) == 0) {
+                       rc = 0;
+                       break;
+               }
+#if 0
+               /* I2C abort */
+               reg_w(ov, R511_I2C_CTL, 0x10);
+#endif
+               if (--retries < 0) {
+                       err("i2c write retries exhausted");
+                       rc = -1;
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+/* NOTE: Do not call this function directly!
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_r(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int
+ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc, value;
+
+       /* Select camera register */
+       rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 2-byte write cycle */
+       rc = reg_w(ov, R518_I2C_CTL, 0x03);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 2-byte read cycle */
+       rc = reg_w(ov, R518_I2C_CTL, 0x05);
+       if (rc < 0)
+               return rc;
+
+       value = reg_r(ov, R51x_I2C_DATA);
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       return value;
+}
+
+/* NOTE: Do not call this function directly!
+ * returns: negative is error, pos or zero is data */
+static int
+ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc, value, retries;
+
+       /* Two byte write cycle */
+       for (retries = OV511_I2C_RETRIES; ; ) {
+               /* Select camera register */
+               rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
+               if (rc < 0)
+                       return rc;
+
+               /* Initiate 2-byte write cycle */
+               rc = reg_w(ov, R511_I2C_CTL, 0x03);
+               if (rc < 0)
+                       return rc;
+
+               /* Retry until idle */
+               do
+                        rc = reg_r(ov, R511_I2C_CTL);
+               while (rc > 0 && ((rc&1) == 0));
+               if (rc < 0)
+                       return rc;
+
+               if ((rc&2) == 0) /* Ack? */
+                       break;
+
+               /* I2C abort */
+               reg_w(ov, R511_I2C_CTL, 0x10);
+
+               if (--retries < 0) {
+                       err("i2c write retries exhausted");
+                       return -1;
+               }
+       }
+
+       /* Two byte read cycle */
+       for (retries = OV511_I2C_RETRIES; ; ) {
+               /* Initiate 2-byte read cycle */
+               rc = reg_w(ov, R511_I2C_CTL, 0x05);
+               if (rc < 0)
+                       return rc;
+
+               /* Retry until idle */
+               do
+                       rc = reg_r(ov, R511_I2C_CTL);
+               while (rc > 0 && ((rc&1) == 0));
+               if (rc < 0)
+                       return rc;
+
+               if ((rc&2) == 0) /* Ack? */
+                       break;
+
+               /* I2C abort */
+               rc = reg_w(ov, R511_I2C_CTL, 0x10);
+               if (rc < 0)
+                       return rc;
+
+               if (--retries < 0) {
+                       err("i2c read retries exhausted");
+                       return -1;
+               }
+       }
+
+       value = reg_r(ov, R51x_I2C_DATA);
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       /* This is needed to make i2c_w() work */
+       rc = reg_w(ov, R511_I2C_CTL, 0x05);
+       if (rc < 0)
+               return rc;
+
+       return value;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int
+i2c_r(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       if (ov->bclass == BCL_OV518)
+               rc = ov518_i2c_read_internal(ov, reg);
+       else
+               rc = ov511_i2c_read_internal(ov, reg);
+
+       mutex_unlock(&ov->i2c_lock);
+
+       return rc;
+}
+
+static int
+i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       if (ov->bclass == BCL_OV518)
+               rc = ov518_i2c_write_internal(ov, reg, value);
+       else
+               rc = ov511_i2c_write_internal(ov, reg, value);
+
+       mutex_unlock(&ov->i2c_lock);
+
+       return rc;
+}
+
+/* Do not call this function directly! */
+static int
+ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
+                             unsigned char reg,
+                             unsigned char value,
+                             unsigned char mask)
+{
+       int rc;
+       unsigned char oldval, newval;
+
+       if (mask == 0xff) {
+               newval = value;
+       } else {
+               if (ov->bclass == BCL_OV518)
+                       rc = ov518_i2c_read_internal(ov, reg);
+               else
+                       rc = ov511_i2c_read_internal(ov, reg);
+               if (rc < 0)
+                       return rc;
+
+               oldval = (unsigned char) rc;
+               oldval &= (~mask);              /* Clear the masked bits */
+               value &= mask;                  /* Enforce mask on value */
+               newval = oldval | value;        /* Set the desired bits */
+       }
+
+       if (ov->bclass == BCL_OV518)
+               return (ov518_i2c_write_internal(ov, reg, newval));
+       else
+               return (ov511_i2c_write_internal(ov, reg, newval));
+}
+
+/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int
+i2c_w_mask(struct usb_ov511 *ov,
+          unsigned char reg,
+          unsigned char value,
+          unsigned char mask)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
+       mutex_unlock(&ov->i2c_lock);
+
+       return rc;
+}
+
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
+ * when calling this. This should not be called from outside the i2c I/O
+ * functions.
+ */
+static int
+i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
+{
+       int rc;
+
+       rc = reg_w(ov, R51x_I2C_W_SID, slave);
+       if (rc < 0)
+               return rc;
+
+       rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+/* Write to a specific I2C slave ID and register, using the specified mask */
+static int
+i2c_w_slave(struct usb_ov511 *ov,
+           unsigned char slave,
+           unsigned char reg,
+           unsigned char value,
+           unsigned char mask)
+{
+       int rc = 0;
+
+       mutex_lock(&ov->i2c_lock);
+
+       /* Set new slave IDs */
+       rc = i2c_set_slave_internal(ov, slave);
+       if (rc < 0)
+               goto out;
+
+       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
+
+out:
+       /* Restore primary IDs */
+       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+               err("Couldn't restore primary I2C slave");
+
+       mutex_unlock(&ov->i2c_lock);
+       return rc;
+}
+
+/* Read from a specific I2C slave ID and register */
+static int
+i2c_r_slave(struct usb_ov511 *ov,
+           unsigned char slave,
+           unsigned char reg)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       /* Set new slave IDs */
+       rc = i2c_set_slave_internal(ov, slave);
+       if (rc < 0)
+               goto out;
+
+       if (ov->bclass == BCL_OV518)
+               rc = ov518_i2c_read_internal(ov, reg);
+       else
+               rc = ov511_i2c_read_internal(ov, reg);
+
+out:
+       /* Restore primary IDs */
+       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+               err("Couldn't restore primary I2C slave");
+
+       mutex_unlock(&ov->i2c_lock);
+       return rc;
+}
+
+/* Sets I2C read and write slave IDs. Returns <0 for error */
+static int
+ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       rc = i2c_set_slave_internal(ov, sid);
+       if (rc < 0)
+               goto out;
+
+       // FIXME: Is this actually necessary?
+       rc = ov51x_reset(ov, OV511_RESET_NOREGS);
+out:
+       mutex_unlock(&ov->i2c_lock);
+       return rc;
+}
+
+static int
+write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
+{
+       int rc;
+
+       while (pRegvals->bus != OV511_DONE_BUS) {
+               if (pRegvals->bus == OV511_REG_BUS) {
+                       if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
+                               return rc;
+               } else if (pRegvals->bus == OV511_I2C_BUS) {
+                       if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
+                               return rc;
+               } else {
+                       err("Bad regval array");
+                       return -1;
+               }
+               pRegvals++;
+       }
+       return 0;
+}
+
+#ifdef OV511_DEBUG
+static void
+dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
+{
+       int i, rc;
+
+       for (i = reg1; i <= regn; i++) {
+               rc = i2c_r(ov, i);
+               info("Sensor[0x%02X] = 0x%02X", i, rc);
+       }
+}
+
+static void
+dump_i2c_regs(struct usb_ov511 *ov)
+{
+       info("I2C REGS");
+       dump_i2c_range(ov, 0x00, 0x7C);
+}
+
+static void
+dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
+{
+       int i, rc;
+
+       for (i = reg1; i <= regn; i++) {
+               rc = reg_r(ov, i);
+               info("OV511[0x%02X] = 0x%02X", i, rc);
+       }
+}
+
+static void
+ov511_dump_regs(struct usb_ov511 *ov)
+{
+       info("CAMERA INTERFACE REGS");
+       dump_reg_range(ov, 0x10, 0x1f);
+       info("DRAM INTERFACE REGS");
+       dump_reg_range(ov, 0x20, 0x23);
+       info("ISO FIFO REGS");
+       dump_reg_range(ov, 0x30, 0x31);
+       info("PIO REGS");
+       dump_reg_range(ov, 0x38, 0x39);
+       dump_reg_range(ov, 0x3e, 0x3e);
+       info("I2C REGS");
+       dump_reg_range(ov, 0x40, 0x49);
+       info("SYSTEM CONTROL REGS");
+       dump_reg_range(ov, 0x50, 0x55);
+       dump_reg_range(ov, 0x5e, 0x5f);
+       info("OmniCE REGS");
+       dump_reg_range(ov, 0x70, 0x79);
+       /* NOTE: Quantization tables are not readable. You will get the value
+        * in reg. 0x79 for every table register */
+       dump_reg_range(ov, 0x80, 0x9f);
+       dump_reg_range(ov, 0xa0, 0xbf);
+
+}
+
+static void
+ov518_dump_regs(struct usb_ov511 *ov)
+{
+       info("VIDEO MODE REGS");
+       dump_reg_range(ov, 0x20, 0x2f);
+       info("DATA PUMP AND SNAPSHOT REGS");
+       dump_reg_range(ov, 0x30, 0x3f);
+       info("I2C REGS");
+       dump_reg_range(ov, 0x40, 0x4f);
+       info("SYSTEM CONTROL AND VENDOR REGS");
+       dump_reg_range(ov, 0x50, 0x5f);
+       info("60 - 6F");
+       dump_reg_range(ov, 0x60, 0x6f);
+       info("70 - 7F");
+       dump_reg_range(ov, 0x70, 0x7f);
+       info("Y QUANTIZATION TABLE");
+       dump_reg_range(ov, 0x80, 0x8f);
+       info("UV QUANTIZATION TABLE");
+       dump_reg_range(ov, 0x90, 0x9f);
+       info("A0 - BF");
+       dump_reg_range(ov, 0xa0, 0xbf);
+       info("CBR");
+       dump_reg_range(ov, 0xc0, 0xcf);
+}
+#endif
+
+/*****************************************************************************/
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int
+ov51x_stop(struct usb_ov511 *ov)
+{
+       PDEBUG(4, "stopping");
+       ov->stopped = 1;
+       if (ov->bclass == BCL_OV518)
+               return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
+       else
+               return (reg_w(ov, R51x_SYS_RESET, 0x3d));
+}
+
+/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
+ * actually stopped (for performance). */
+static inline int
+ov51x_restart(struct usb_ov511 *ov)
+{
+       if (ov->stopped) {
+               PDEBUG(4, "restarting");
+               ov->stopped = 0;
+
+               /* Reinitialize the stream */
+               if (ov->bclass == BCL_OV518)
+                       reg_w(ov, 0x2f, 0x80);
+
+               return (reg_w(ov, R51x_SYS_RESET, 0x00));
+       }
+
+       return 0;
+}
+
+/* Sleeps until no frames are active. Returns !0 if got signal */
+static int
+ov51x_wait_frames_inactive(struct usb_ov511 *ov)
+{
+       return wait_event_interruptible(ov->wq, ov->curframe < 0);
+}
+
+/* Resets the hardware snapshot button */
+static void
+ov51x_clear_snapshot(struct usb_ov511 *ov)
+{
+       if (ov->bclass == BCL_OV511) {
+               reg_w(ov, R51x_SYS_SNAP, 0x00);
+               reg_w(ov, R51x_SYS_SNAP, 0x02);
+               reg_w(ov, R51x_SYS_SNAP, 0x00);
+       } else if (ov->bclass == BCL_OV518) {
+               warn("snapshot reset not supported yet on OV518(+)");
+       } else {
+               err("clear snap: invalid bridge type");
+       }
+}
+
+#if 0
+/* Checks the status of the snapshot button. Returns 1 if it was pressed since
+ * it was last cleared, and zero in all other cases (including errors) */
+static int
+ov51x_check_snapshot(struct usb_ov511 *ov)
+{
+       int ret, status = 0;
+
+       if (ov->bclass == BCL_OV511) {
+               ret = reg_r(ov, R51x_SYS_SNAP);
+               if (ret < 0) {
+                       err("Error checking snspshot status (%d)", ret);
+               } else if (ret & 0x08) {
+                       status = 1;
+               }
+       } else if (ov->bclass == BCL_OV518) {
+               warn("snapshot check not supported yet on OV518(+)");
+       } else {
+               err("check snap: invalid bridge type");
+       }
+
+       return status;
+}
+#endif
+
+/* This does an initial reset of an OmniVision sensor and ensures that I2C
+ * is synchronized. Returns <0 for failure.
+ */
+static int
+init_ov_sensor(struct usb_ov511 *ov)
+{
+       int i, success;
+
+       /* Reset the sensor */
+       if (i2c_w(ov, 0x12, 0x80) < 0)
+               return -EIO;
+
+       /* Wait for it to initialize */
+       msleep(150);
+
+       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+               if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
+                   (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
+                       success = 1;
+                       continue;
+               }
+
+               /* Reset the sensor */
+               if (i2c_w(ov, 0x12, 0x80) < 0)
+                       return -EIO;
+               /* Wait for it to initialize */
+               msleep(150);
+               /* Dummy read to sync I2C */
+               if (i2c_r(ov, 0x00) < 0)
+                       return -EIO;
+       }
+
+       if (!success)
+               return -EIO;
+
+       PDEBUG(1, "I2C synced in %d attempt(s)", i);
+
+       return 0;
+}
+
+static int
+ov511_set_packet_size(struct usb_ov511 *ov, int size)
+{
+       int alt, mult;
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       mult = size >> 5;
+
+       if (ov->bridge == BRG_OV511) {
+               if (size == 0)
+                       alt = OV511_ALT_SIZE_0;
+               else if (size == 257)
+                       alt = OV511_ALT_SIZE_257;
+               else if (size == 513)
+                       alt = OV511_ALT_SIZE_513;
+               else if (size == 769)
+                       alt = OV511_ALT_SIZE_769;
+               else if (size == 993)
+                       alt = OV511_ALT_SIZE_993;
+               else {
+                       err("Set packet size: invalid size (%d)", size);
+                       return -EINVAL;
+               }
+       } else if (ov->bridge == BRG_OV511PLUS) {
+               if (size == 0)
+                       alt = OV511PLUS_ALT_SIZE_0;
+               else if (size == 33)
+                       alt = OV511PLUS_ALT_SIZE_33;
+               else if (size == 129)
+                       alt = OV511PLUS_ALT_SIZE_129;
+               else if (size == 257)
+                       alt = OV511PLUS_ALT_SIZE_257;
+               else if (size == 385)
+                       alt = OV511PLUS_ALT_SIZE_385;
+               else if (size == 513)
+                       alt = OV511PLUS_ALT_SIZE_513;
+               else if (size == 769)
+                       alt = OV511PLUS_ALT_SIZE_769;
+               else if (size == 961)
+                       alt = OV511PLUS_ALT_SIZE_961;
+               else {
+                       err("Set packet size: invalid size (%d)", size);
+                       return -EINVAL;
+               }
+       } else {
+               err("Set packet size: Invalid bridge type");
+               return -EINVAL;
+       }
+
+       PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
+
+       if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
+               return -EIO;
+
+       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
+               err("Set packet size: set interface error");
+               return -EBUSY;
+       }
+
+       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+               return -EIO;
+
+       ov->packet_size = size;
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
+ * optional packet number byte. The actual size *is* stored in ov->packet_size,
+ * though. */
+static int
+ov518_set_packet_size(struct usb_ov511 *ov, int size)
+{
+       int alt;
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       if (ov->bclass == BCL_OV518) {
+               if (size == 0)
+                       alt = OV518_ALT_SIZE_0;
+               else if (size == 128)
+                       alt = OV518_ALT_SIZE_128;
+               else if (size == 256)
+                       alt = OV518_ALT_SIZE_256;
+               else if (size == 384)
+                       alt = OV518_ALT_SIZE_384;
+               else if (size == 512)
+                       alt = OV518_ALT_SIZE_512;
+               else if (size == 640)
+                       alt = OV518_ALT_SIZE_640;
+               else if (size == 768)
+                       alt = OV518_ALT_SIZE_768;
+               else if (size == 896)
+                       alt = OV518_ALT_SIZE_896;
+               else {
+                       err("Set packet size: invalid size (%d)", size);
+                       return -EINVAL;
+               }
+       } else {
+               err("Set packet size: Invalid bridge type");
+               return -EINVAL;
+       }
+
+       PDEBUG(3, "%d, alt=%d", size, alt);
+
+       ov->packet_size = size;
+       if (size > 0) {
+               /* Program ISO FIFO size reg (packet number isn't included) */
+               ov518_reg_w32(ov, 0x30, size, 2);
+
+               if (ov->packet_numbering)
+                       ++ov->packet_size;
+       }
+
+       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
+               err("Set packet size: set interface error");
+               return -EBUSY;
+       }
+
+       /* Initialize the stream */
+       if (reg_w(ov, 0x2f, 0x80) < 0)
+               return -EIO;
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* Upload compression params and quantization tables. Returns 0 for success. */
+static int
+ov511_init_compression(struct usb_ov511 *ov)
+{
+       int rc = 0;
+
+       if (!ov->compress_inited) {
+               reg_w(ov, 0x70, phy);
+               reg_w(ov, 0x71, phuv);
+               reg_w(ov, 0x72, pvy);
+               reg_w(ov, 0x73, pvuv);
+               reg_w(ov, 0x74, qhy);
+               reg_w(ov, 0x75, qhuv);
+               reg_w(ov, 0x76, qvy);
+               reg_w(ov, 0x77, qvuv);
+
+               if (ov511_upload_quan_tables(ov) < 0) {
+                       err("Error uploading quantization tables");
+                       rc = -EIO;
+                       goto out;
+               }
+       }
+
+       ov->compress_inited = 1;
+out:
+       return rc;
+}
+
+/* Upload compression params and quantization tables. Returns 0 for success. */
+static int
+ov518_init_compression(struct usb_ov511 *ov)
+{
+       int rc = 0;
+
+       if (!ov->compress_inited) {
+               if (ov518_upload_quan_tables(ov) < 0) {
+                       err("Error uploading quantization tables");
+                       rc = -EIO;
+                       goto out;
+               }
+       }
+
+       ov->compress_inited = 1;
+out:
+       return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's contrast setting to "val" */
+static int
+sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       {
+               rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       case SEN_OV6630:
+       {
+               rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       case SEN_OV7620:
+       {
+               unsigned char ctab[] = {
+                       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
+                       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
+               };
+
+               /* Use Y gamma control instead. Bit 0 enables it. */
+               rc = i2c_w(ov, 0x64, ctab[val>>12]);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       case SEN_SAA7111A:
+       {
+               rc = i2c_w(ov, 0x0b, val >> 9);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       default:
+       {
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+       }
+
+       rc = 0;         /* Success */
+       ov->contrast = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's contrast setting */
+static int
+sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+               rc = i2c_r(ov, OV7610_REG_CNT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_CNT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 12;
+               break;
+       case SEN_OV7620:
+               /* Use Y gamma reg instead. Bit 0 is the enable bit. */
+               rc = i2c_r(ov, 0x64);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = (rc & 0xfe) << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->contrast;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->contrast = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's brightness setting to "val" */
+static int
+sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(4, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_OV7620:
+               /* 7620 doesn't like manual changes when in auto mode */
+               if (!ov->auto_brt) {
+                       rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
+                       if (rc < 0)
+                               goto out;
+               }
+               break;
+       case SEN_SAA7111A:
+               rc = i2c_w(ov, 0x0a, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+
+       rc = 0;         /* Success */
+       ov->brightness = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's brightness setting */
+static int
+sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV7620:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_BRT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->brightness;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->brightness = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's saturation (color intensity) setting to "val" */
+static int
+sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_OV7620:
+//             /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
+//             rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
+//             if (rc < 0)
+//                     goto out;
+               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_SAA7111A:
+               rc = i2c_w(ov, 0x0c, val >> 9);
+               if (rc < 0)
+                       goto out;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+
+       rc = 0;         /* Success */
+       ov->colour = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's saturation (color intensity) setting */
+static int
+sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_SAT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_OV7620:
+//             /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
+//             rc = i2c_r(ov, 0x62);
+//             if (rc < 0)
+//                     return rc;
+//             else
+//                     *val = (rc & 0x7e) << 9;
+               rc = i2c_r(ov, OV7610_REG_SAT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->colour;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->colour = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's hue (red/blue balance) setting to "val" */
+static int
+sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
+               if (rc < 0)
+                       goto out;
+
+               rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_OV7620:
+// Hue control is causing problems. I will enable it once it's fixed.
+#if 0
+               rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
+               if (rc < 0)
+                       goto out;
+
+               rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
+               if (rc < 0)
+                       goto out;
+#endif
+               break;
+       case SEN_SAA7111A:
+               rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+
+       rc = 0;         /* Success */
+       ov->hue = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's hue (red/blue balance) setting */
+static int
+sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_BLUE);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_OV7620:
+               rc = i2c_r(ov, 0x7a);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->hue;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->hue = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int
+sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
+{
+       int rc;
+
+       PDEBUG(4, "sensor_set_picture");
+
+       ov->whiteness = p->whiteness;
+
+       /* Don't return error if a setting is unsupported, or rest of settings
+        * will not be performed */
+
+       rc = sensor_set_contrast(ov, p->contrast);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_brightness(ov, p->brightness);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_saturation(ov, p->colour);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_hue(ov, p->hue);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       return 0;
+}
+
+static int
+sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
+{
+       int rc;
+
+       PDEBUG(4, "sensor_get_picture");
+
+       /* Don't return error if a setting is unsupported, or rest of settings
+        * will not be performed */
+
+       rc = sensor_get_contrast(ov, &(p->contrast));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_get_brightness(ov, &(p->brightness));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_get_saturation(ov, &(p->colour));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_get_hue(ov, &(p->hue));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       p->whiteness = 105 << 8;
+
+       return 0;
+}
+
+#if 0
+// FIXME: Exposure range is only 0x00-0x7f in interlace mode
+/* Sets current exposure for sensor. This only has an effect if auto-exposure
+ * is off */
+static inline int
+sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7610:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               rc = i2c_w(ov, 0x10, val);
+               if (rc < 0)
+                       goto out;
+
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_exposure");
+               return -EINVAL;
+       }
+
+       rc = 0;         /* Success */
+       ov->exposure = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+#endif
+
+/* Gets current exposure level from sensor, regardless of whether it is under
+ * manual control. */
+static int
+sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               rc = i2c_r(ov, 0x10);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc;
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               val = NULL;
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for get_exposure");
+               return -EINVAL;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->exposure = *val;
+
+       return 0;
+}
+
+/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
+static void
+ov51x_led_control(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       if (ov->bridge == BRG_OV511PLUS)
+               reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
+       else if (ov->bclass == BCL_OV518)
+               reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
+
+       return;
+}
+
+/* Matches the sensor's internal frame rate to the lighting frequency.
+ * Valid frequencies are:
+ *     50 - 50Hz, for European and Asian lighting
+ *     60 - 60Hz, for American lighting
+ *
+ * Tested with: OV7610, OV7620, OV76BE, OV6620
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_light_freq(struct usb_ov511 *ov, int freq)
+{
+       int sixty;
+
+       PDEBUG(4, "%d Hz", freq);
+
+       if (freq == 60)
+               sixty = 1;
+       else if (freq == 50)
+               sixty = 0;
+       else {
+               err("Invalid light freq (%d Hz)", freq);
+               return -EINVAL;
+       }
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
+               i2c_w(ov, 0x2b, sixty?0x00:0xac);
+               i2c_w_mask(ov, 0x13, 0x10, 0x10);
+               i2c_w_mask(ov, 0x13, 0x00, 0x10);
+               break;
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
+               i2c_w(ov, 0x2b, sixty?0x00:0xac);
+               i2c_w_mask(ov, 0x76, 0x01, 0x01);
+               break;
+       case SEN_OV6620:
+       case SEN_OV6630:
+               i2c_w(ov, 0x2b, sixty?0xa8:0x28);
+               i2c_w(ov, 0x2a, sixty?0x84:0xa4);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_light_freq");
+               return -EINVAL;
+       }
+
+       ov->lightfreq = freq;
+
+       return 0;
+}
+
+/* If enable is true, turn on the sensor's banding filter, otherwise turn it
+ * off. This filter tries to reduce the pattern of horizontal light/dark bands
+ * caused by some (usually fluorescent) lighting. The light frequency must be
+ * set either before or after enabling it with ov51x_set_light_freq().
+ *
+ * Tested with: OV7610, OV7620, OV76BE, OV6620.
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
+{
+       int rc;
+
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
+               || ov->sensor == SEN_SAA7111A) {
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
+       if (rc < 0)
+               return rc;
+
+       ov->bandfilt = enable;
+
+       return 0;
+}
+
+/* If enable is true, turn on the sensor's auto brightness control, otherwise
+ * turn it off.
+ *
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
+{
+       int rc;
+
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
+               || ov->sensor == SEN_SAA7111A) {
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
+       if (rc < 0)
+               return rc;
+
+       ov->auto_brt = enable;
+
+       return 0;
+}
+
+/* If enable is true, turn on the sensor's auto exposure control, otherwise
+ * turn it off.
+ *
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+               i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
+               break;
+       case SEN_OV6620:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
+               break;
+       case SEN_OV6630:
+               i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_auto_exposure");
+               return -EINVAL;
+       }
+
+       ov->auto_exp = enable;
+
+       return 0;
+}
+
+/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
+ * that are illuminated from behind.
+ *
+ * Tested with: OV6620, OV7620
+ * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_backlight(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       switch (ov->sensor) {
+       case SEN_OV7620:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
+               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
+               break;
+       case SEN_OV6620:
+               i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
+               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+               i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
+               break;
+       case SEN_OV6630:
+               i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
+               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
+               break;
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_backlight");
+               return -EINVAL;
+       }
+
+       ov->backlight = enable;
+
+       return 0;
+}
+
+static int
+sensor_set_mirror(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       switch (ov->sensor) {
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7610:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_mirror");
+               return -EINVAL;
+       }
+
+       ov->mirror = enable;
+
+       return 0;
+}
+
+/* Returns number of bits per pixel (regardless of where they are located;
+ * planar or not), or zero for unsupported format.
+ */
+static inline int
+get_depth(int palette)
+{
+       switch (palette) {
+       case VIDEO_PALETTE_GREY:    return 8;
+       case VIDEO_PALETTE_YUV420:  return 12;
+       case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
+       default:                    return 0;  /* Invalid format */
+       }
+}
+
+/* Bytes per frame. Used by read(). Return of 0 indicates error */
+static inline long int
+get_frame_length(struct ov511_frame *frame)
+{
+       if (!frame)
+               return 0;
+       else
+               return ((frame->width * frame->height
+                        * get_depth(frame->format)) >> 3);
+}
+
+static int
+mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
+                        int mode, int sub_flag, int qvga)
+{
+       int clock;
+
+       /******** Mode (VGA/QVGA) and sensor specific regs ********/
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+               i2c_w(ov, 0x14, qvga?0x24:0x04);
+// FIXME: Does this improve the image quality or frame rate?
+#if 0
+               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+               i2c_w(ov, 0x24, 0x10);
+               i2c_w(ov, 0x25, qvga?0x40:0x8a);
+               i2c_w(ov, 0x2f, qvga?0x30:0xb0);
+               i2c_w(ov, 0x35, qvga?0x1c:0x9c);
+#endif
+               break;
+       case SEN_OV7620:
+//             i2c_w(ov, 0x2b, 0x00);
+               i2c_w(ov, 0x14, qvga?0xa4:0x84);
+               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+               i2c_w(ov, 0x24, qvga?0x20:0x3a);
+               i2c_w(ov, 0x25, qvga?0x30:0x60);
+               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
+               i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
+               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
+               break;
+       case SEN_OV76BE:
+//             i2c_w(ov, 0x2b, 0x00);
+               i2c_w(ov, 0x14, qvga?0xa4:0x84);
+// FIXME: Enable this once 7620AE uses 7620 initial settings
+#if 0
+               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+               i2c_w(ov, 0x24, qvga?0x20:0x3a);
+               i2c_w(ov, 0x25, qvga?0x30:0x60);
+               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
+               i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
+               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
+#endif
+               break;
+       case SEN_OV6620:
+               i2c_w(ov, 0x14, qvga?0x24:0x04);
+               break;
+       case SEN_OV6630:
+               i2c_w(ov, 0x14, qvga?0xa0:0x80);
+               break;
+       default:
+               err("Invalid sensor");
+               return -EINVAL;
+       }
+
+       /******** Palette-specific regs ********/
+
+       if (mode == VIDEO_PALETTE_GREY) {
+               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
+                       /* these aren't valid on the OV6620/OV7620/6630? */
+                       i2c_w_mask(ov, 0x0e, 0x40, 0x40);
+               }
+
+               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
+                   && ov518_color) {
+                       i2c_w_mask(ov, 0x12, 0x00, 0x10);
+                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
+               } else {
+                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
+               }
+       } else {
+               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
+                       /* not valid on the OV6620/OV7620/6630? */
+                       i2c_w_mask(ov, 0x0e, 0x00, 0x40);
+               }
+
+               /* The OV518 needs special treatment. Although both the OV518
+                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+                * bus is actually used. The UV bus is tied to ground.
+                * Therefore, the OV6630 needs to be in 8-bit multiplexed
+                * output mode */
+
+               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
+                   && ov518_color) {
+                       i2c_w_mask(ov, 0x12, 0x10, 0x10);
+                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
+               } else {
+                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
+               }
+       }
+
+       /******** Clock programming ********/
+
+       /* The OV6620 needs special handling. This prevents the
+        * severe banding that normally occurs */
+       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
+       {
+               /* Clock down */
+
+               i2c_w(ov, 0x2a, 0x04);
+
+               if (ov->compress) {
+//                     clock = 0;    /* This ensures the highest frame rate */
+                       clock = 3;
+               } else if (clockdiv == -1) {   /* If user didn't override it */
+                       clock = 3;    /* Gives better exposure time */
+               } else {
+                       clock = clockdiv;
+               }
+
+               PDEBUG(4, "Setting clock divisor to %d", clock);
+
+               i2c_w(ov, 0x11, clock);
+
+               i2c_w(ov, 0x2a, 0x84);
+               /* This next setting is critical. It seems to improve
+                * the gain or the contrast. The "reserved" bits seem
+                * to have some effect in this case. */
+               i2c_w(ov, 0x2d, 0x85);
+       }
+       else
+       {
+               if (ov->compress) {
+                       clock = 1;    /* This ensures the highest frame rate */
+               } else if (clockdiv == -1) {   /* If user didn't override it */
+                       /* Calculate and set the clock divisor */
+                       clock = ((sub_flag ? ov->subw * ov->subh
+                                 : width * height)
+                                * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
+                                / 66000;
+               } else {
+                       clock = clockdiv;
+               }
+
+               PDEBUG(4, "Setting clock divisor to %d", clock);
+
+               i2c_w(ov, 0x11, clock);
+       }
+
+       /******** Special Features ********/
+
+       if (framedrop >= 0)
+               i2c_w(ov, 0x16, framedrop);
+
+       /* Test Pattern */
+       i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
+
+       /* Enable auto white balance */
+       i2c_w_mask(ov, 0x12, 0x04, 0x04);
+
+       // This will go away as soon as ov51x_mode_init_sensor_regs()
+       // is fully tested.
+       /* 7620/6620/6630? don't have register 0x35, so play it safe */
+       if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
+               if (width == 640 && height == 480)
+                       i2c_w(ov, 0x35, 0x9e);
+               else
+                       i2c_w(ov, 0x35, 0x1e);
+       }
+
+       return 0;
+}
+
+static int
+set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
+                    int sub_flag)
+{
+       int ret;
+       int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize;
+       int hoffset, voffset, hwscale = 0, vwscale = 0;
+
+       /* The different sensor ICs handle setting up of window differently.
+        * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+               hwsbase = 0x38;
+               hwebase = 0x3a;
+               vwsbase = vwebase = 0x05;
+               break;
+       case SEN_OV6620:
+       case SEN_OV6630:
+               hwsbase = 0x38;
+               hwebase = 0x3a;
+               vwsbase = 0x05;
+               vwebase = 0x06;
+               break;
+       case SEN_OV7620:
+               hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
+               hwebase = 0x2f;
+               vwsbase = vwebase = 0x05;
+               break;
+       default:
+               err("Invalid sensor");
+               return -EINVAL;
+       }
+
+       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
+               /* Note: OV518(+) does downsample on its own) */
+               if ((width > 176 && height > 144)
+                   || ov->bclass == BCL_OV518) {  /* CIF */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 0);
+                       if (ret < 0)
+                               return ret;
+                       hwscale = 1;
+                       vwscale = 1;  /* The datasheet says 0; it's wrong */
+                       hwsize = 352;
+                       vwsize = 288;
+               } else if (width > 176 || height > 144) {
+                       err("Illegal dimensions");
+                       return -EINVAL;
+               } else {                            /* QCIF */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 1);
+                       if (ret < 0)
+                               return ret;
+                       hwsize = 176;
+                       vwsize = 144;
+               }
+       } else {
+               if (width > 320 && height > 240) {  /* VGA */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 0);
+                       if (ret < 0)
+                               return ret;
+                       hwscale = 2;
+                       vwscale = 1;
+                       hwsize = 640;
+                       vwsize = 480;
+               } else if (width > 320 || height > 240) {
+                       err("Illegal dimensions");
+                       return -EINVAL;
+               } else {                            /* QVGA */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 1);
+                       if (ret < 0)
+                               return ret;
+                       hwscale = 1;
+                       hwsize = 320;
+                       vwsize = 240;
+               }
+       }
+
+       /* Center the window */
+       hoffset = ((hwsize - width) / 2) >> hwscale;
+       voffset = ((vwsize - height) / 2) >> vwscale;
+
+       /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
+       if (sub_flag) {
+               i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
+               i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
+               i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
+               i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
+       } else {
+               i2c_w(ov, 0x17, hwsbase + hoffset);
+               i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
+               i2c_w(ov, 0x19, vwsbase + voffset);
+               i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
+       }
+
+#ifdef OV511_DEBUG
+       if (dump_sensor)
+               dump_i2c_regs(ov);
+#endif
+
+       return 0;
+}
+
+/* Set up the OV511/OV511+ with the given image parameters.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int
+ov511_mode_init_regs(struct usb_ov511 *ov,
+                    int width, int height, int mode, int sub_flag)
+{
+       int hsegs, vsegs;
+
+       if (sub_flag) {
+               width = ov->subw;
+               height = ov->subh;
+       }
+
+       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
+              width, height, mode, sub_flag);
+
+       // FIXME: This should be moved to a 7111a-specific function once
+       // subcapture is dealt with properly
+       if (ov->sensor == SEN_SAA7111A) {
+               if (width == 320 && height == 240) {
+                       /* No need to do anything special */
+               } else if (width == 640 && height == 480) {
+                       /* Set the OV511 up as 320x480, but keep the
+                        * V4L resolution as 640x480 */
+                       width = 320;
+               } else {
+                       err("SAA7111A only allows 320x240 or 640x480");
+                       return -EINVAL;
+               }
+       }
+
+       /* Make sure width and height are a multiple of 8 */
+       if (width % 8 || height % 8) {
+               err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
+               return -EINVAL;
+       }
+
+       if (width < ov->minwidth || height < ov->minheight) {
+               err("Requested dimensions are too small");
+               return -EINVAL;
+       }
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       if (mode == VIDEO_PALETTE_GREY) {
+               reg_w(ov, R511_CAM_UV_EN, 0x00);
+               reg_w(ov, R511_SNAP_UV_EN, 0x00);
+               reg_w(ov, R511_SNAP_OPTS, 0x01);
+       } else {
+               reg_w(ov, R511_CAM_UV_EN, 0x01);
+               reg_w(ov, R511_SNAP_UV_EN, 0x01);
+               reg_w(ov, R511_SNAP_OPTS, 0x03);
+       }
+
+       /* Here I'm assuming that snapshot size == image size.
+        * I hope that's always true. --claudio
+        */
+       hsegs = (width >> 3) - 1;
+       vsegs = (height >> 3) - 1;
+
+       reg_w(ov, R511_CAM_PXCNT, hsegs);
+       reg_w(ov, R511_CAM_LNCNT, vsegs);
+       reg_w(ov, R511_CAM_PXDIV, 0x00);
+       reg_w(ov, R511_CAM_LNDIV, 0x00);
+
+       /* YUV420, low pass filter on */
+       reg_w(ov, R511_CAM_OPTS, 0x03);
+
+       /* Snapshot additions */
+       reg_w(ov, R511_SNAP_PXCNT, hsegs);
+       reg_w(ov, R511_SNAP_LNCNT, vsegs);
+       reg_w(ov, R511_SNAP_PXDIV, 0x00);
+       reg_w(ov, R511_SNAP_LNDIV, 0x00);
+
+       if (ov->compress) {
+               /* Enable Y and UV quantization and compression */
+               reg_w(ov, R511_COMP_EN, 0x07);
+               reg_w(ov, R511_COMP_LUT_EN, 0x03);
+               ov51x_reset(ov, OV511_RESET_OMNICE);
+       }
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* Sets up the OV518/OV518+ with the given image parameters
+ *
+ * OV518 needs a completely different approach, until we can figure out what
+ * the individual registers do. Also, only 15 FPS is supported now.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int
+ov518_mode_init_regs(struct usb_ov511 *ov,
+                    int width, int height, int mode, int sub_flag)
+{
+       int hsegs, vsegs, hi_res;
+
+       if (sub_flag) {
+               width = ov->subw;
+               height = ov->subh;
+       }
+
+       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
+              width, height, mode, sub_flag);
+
+       if (width % 16 || height % 8) {
+               err("Invalid size (%d, %d)", width, height);
+               return -EINVAL;
+       }
+
+       if (width < ov->minwidth || height < ov->minheight) {
+               err("Requested dimensions are too small");
+               return -EINVAL;
+       }
+
+       if (width >= 320 && height >= 240) {
+               hi_res = 1;
+       } else if (width >= 320 || height >= 240) {
+               err("Invalid width/height combination (%d, %d)", width, height);
+               return -EINVAL;
+       } else {
+               hi_res = 0;
+       }
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       /******** Set the mode ********/
+
+       reg_w(ov, 0x2b, 0);
+       reg_w(ov, 0x2c, 0);
+       reg_w(ov, 0x2d, 0);
+       reg_w(ov, 0x2e, 0);
+       reg_w(ov, 0x3b, 0);
+       reg_w(ov, 0x3c, 0);
+       reg_w(ov, 0x3d, 0);
+       reg_w(ov, 0x3e, 0);
+
+       if (ov->bridge == BRG_OV518 && ov518_color) {
+               /* OV518 needs U and V swapped */
+               i2c_w_mask(ov, 0x15, 0x00, 0x01);
+
+               if (mode == VIDEO_PALETTE_GREY) {
+                       /* Set 16-bit input format (UV data are ignored) */
+                       reg_w_mask(ov, 0x20, 0x00, 0x08);
+
+                       /* Set 8-bit (4:0:0) output format */
+                       reg_w_mask(ov, 0x28, 0x00, 0xf0);
+                       reg_w_mask(ov, 0x38, 0x00, 0xf0);
+               } else {
+                       /* Set 8-bit (YVYU) input format */
+                       reg_w_mask(ov, 0x20, 0x08, 0x08);
+
+                       /* Set 12-bit (4:2:0) output format */
+                       reg_w_mask(ov, 0x28, 0x80, 0xf0);
+                       reg_w_mask(ov, 0x38, 0x80, 0xf0);
+               }
+       } else {
+               reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+               reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+       }
+
+       hsegs = width / 16;
+       vsegs = height / 4;
+
+       reg_w(ov, 0x29, hsegs);
+       reg_w(ov, 0x2a, vsegs);
+
+       reg_w(ov, 0x39, hsegs);
+       reg_w(ov, 0x3a, vsegs);
+
+       /* Windows driver does this here; who knows why */
+       reg_w(ov, 0x2f, 0x80);
+
+       /******** Set the framerate (to 15 FPS) ********/
+
+       /* Mode independent, but framerate dependent, regs */
+       reg_w(ov, 0x51, 0x02);  /* Clock divider; lower==faster */
+       reg_w(ov, 0x22, 0x18);
+       reg_w(ov, 0x23, 0xff);
+
+       if (ov->bridge == BRG_OV518PLUS)
+               reg_w(ov, 0x21, 0x19);
+       else
+               reg_w(ov, 0x71, 0x19);  /* Compression-related? */
+
+       // FIXME: Sensor-specific
+       /* Bit 5 is what matters here. Of course, it is "reserved" */
+       i2c_w(ov, 0x54, 0x23);
+
+       reg_w(ov, 0x2f, 0x80);
+
+       if (ov->bridge == BRG_OV518PLUS) {
+               reg_w(ov, 0x24, 0x94);
+               reg_w(ov, 0x25, 0x90);
+               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(ov, 0xc6,    540, 2);     /* 21ch   */
+               ov518_reg_w32(ov, 0xc7,    540, 2);     /* 21ch   */
+               ov518_reg_w32(ov, 0xc8,    108, 2);     /* 6ch    */
+               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(ov, 0xcc,   2400, 2);     /* 960h   */
+               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
+       } else {
+               reg_w(ov, 0x24, 0x9f);
+               reg_w(ov, 0x25, 0x90);
+               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(ov, 0xc6,    500, 2);     /* 1f4h   */
+               ov518_reg_w32(ov, 0xc7,    500, 2);     /* 1f4h   */
+               ov518_reg_w32(ov, 0xc8,    142, 2);     /* 8eh    */
+               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(ov, 0xcc,   2000, 2);     /* 7d0h   */
+               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
+       }
+
+       reg_w(ov, 0x2f, 0x80);
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       /* Reset it just for good measure */
+       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* This is a wrapper around the OV511, OV518, and sensor specific functions */
+static int
+mode_init_regs(struct usb_ov511 *ov,
+              int width, int height, int mode, int sub_flag)
+{
+       int rc = 0;
+
+       if (!ov || !ov->dev)
+               return -EFAULT;
+
+       if (ov->bclass == BCL_OV518) {
+               rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
+       } else {
+               rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
+       }
+
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+               err("KS0127-series decoders not supported yet");
+               rc = -EINVAL;
+               break;
+       case SEN_SAA7111A:
+//             rc = mode_init_saa_sensor_regs(ov, width, height, mode,
+//                                            sub_flag);
+
+               PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
+               break;
+       default:
+               err("Unknown sensor");
+               rc = -EINVAL;
+       }
+
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       /* Sensor-independent settings */
+       rc = sensor_set_auto_brightness(ov, ov->auto_brt);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_auto_exposure(ov, ov->auto_exp);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_banding_filter(ov, bandingfilter);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       if (ov->lightfreq) {
+               rc = sensor_set_light_freq(ov, lightfreq);
+               if (FATAL_ERROR(rc))
+                       return rc;
+       }
+
+       rc = sensor_set_backlight(ov, ov->backlight);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_mirror(ov, ov->mirror);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       return 0;
+}
+
+/* This sets the default image parameters. This is useful for apps that use
+ * read() and do not set these.
+ */
+static int
+ov51x_set_default_params(struct usb_ov511 *ov)
+{
+       int i;
+
+       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
+        * (using read() instead). */
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].width = ov->maxwidth;
+               ov->frame[i].height = ov->maxheight;
+               ov->frame[i].bytes_read = 0;
+               if (force_palette)
+                       ov->frame[i].format = force_palette;
+               else
+                       ov->frame[i].format = VIDEO_PALETTE_YUV420;
+
+               ov->frame[i].depth = get_depth(ov->frame[i].format);
+       }
+
+       PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
+              symbolic(v4l1_plist, ov->frame[0].format));
+
+       /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
+       if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
+                          ov->frame[0].format, 0) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**********************************************************************
+ *
+ * Video decoder stuff
+ *
+ **********************************************************************/
+
+/* Set analog input port of decoder */
+static int
+decoder_set_input(struct usb_ov511 *ov, int input)
+{
+       PDEBUG(4, "port %d", input);
+
+       switch (ov->sensor) {
+       case SEN_SAA7111A:
+       {
+               /* Select mode */
+               i2c_w_mask(ov, 0x02, input, 0x07);
+               /* Bypass chrominance trap for modes 4..7 */
+               i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Get ASCII name of video input */
+static int
+decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
+{
+       switch (ov->sensor) {
+       case SEN_SAA7111A:
+       {
+               if (input < 0 || input > 7)
+                       return -EINVAL;
+               else if (input < 4)
+                       sprintf(name, "CVBS-%d", input);
+               else // if (input < 8)
+                       sprintf(name, "S-Video-%d", input - 4);
+               break;
+       }
+       default:
+               sprintf(name, "%s", "Camera");
+       }
+
+       return 0;
+}
+
+/* Set norm (NTSC, PAL, SECAM, AUTO) */
+static int
+decoder_set_norm(struct usb_ov511 *ov, int norm)
+{
+       PDEBUG(4, "%d", norm);
+
+       switch (ov->sensor) {
+       case SEN_SAA7111A:
+       {
+               int reg_8, reg_e;
+
+               if (norm == VIDEO_MODE_NTSC) {
+                       reg_8 = 0x40;   /* 60 Hz */
+                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
+               } else if (norm == VIDEO_MODE_PAL) {
+                       reg_8 = 0x00;   /* 50 Hz */
+                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
+               } else if (norm == VIDEO_MODE_AUTO) {
+                       reg_8 = 0x80;   /* Auto field detect */
+                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
+               } else if (norm == VIDEO_MODE_SECAM) {
+                       reg_8 = 0x00;   /* 50 Hz */
+                       reg_e = 0x50;   /* SECAM / PAL 4.43 */
+               } else {
+                       return -EINVAL;
+               }
+
+               i2c_w_mask(ov, 0x08, reg_8, 0xc0);
+               i2c_w_mask(ov, 0x0e, reg_e, 0x70);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**********************************************************************
+ *
+ * Raw data parsing
+ *
+ **********************************************************************/
+
+/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
+ * image at pOut is specified by w.
+ */
+static inline void
+make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
+{
+       unsigned char *pOut1 = pOut;
+       int x, y;
+
+       for (y = 0; y < 8; y++) {
+               pOut1 = pOut;
+               for (x = 0; x < 8; x++) {
+                       *pOut1++ = *pIn++;
+               }
+               pOut += w;
+       }
+}
+
+/*
+ * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
+ * The segments represent 4 squares of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121 ... 127        248 249 ... 255
+ *
+ */
+static void
+yuv400raw_to_yuv400p(struct ov511_frame *frame,
+                    unsigned char *pIn0, unsigned char *pOut0)
+{
+       int x, y;
+       unsigned char *pIn, *pOut, *pOutLine;
+
+       /* Copy Y */
+       pIn = pIn0;
+       pOutLine = pOut0;
+       for (y = 0; y < frame->rawheight - 1; y += 8) {
+               pOut = pOutLine;
+               for (x = 0; x < frame->rawwidth - 1; x += 8) {
+                       make_8x8(pIn, pOut, frame->rawwidth);
+                       pIn += 64;
+                       pOut += 8;
+               }
+               pOutLine += 8 * frame->rawwidth;
+       }
+}
+
+/*
+ * For YUV 4:2:0 images, the data show up in 384 byte segments.
+ * The first 64 bytes of each segment are U, the next 64 are V.  The U and
+ * V are arranged as follows:
+ *
+ *      0  1 ...  7
+ *      8  9 ... 15
+ *           ...
+ *     56 57 ... 63
+ *
+ * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
+ *
+ * The next 256 bytes are full resolution Y data and represent 4 squares
+ * of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
+ *
+ * Note that the U and V data in one segment represent a 16 x 16 pixel
+ * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
+ * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
+ * next horizontal stripe.
+ *
+ * If dumppix module param is set, _parse_data just dumps the incoming segments,
+ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
+ * this puts the data on the standard output and can be analyzed with the
+ * parseppm.c utility I wrote.  That's a much faster way for figuring out how
+ * these data are scrambled.
+ */
+
+/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
+ *
+ * FIXME: Currently only handles width and height that are multiples of 16
+ */
+static void
+yuv420raw_to_yuv420p(struct ov511_frame *frame,
+                    unsigned char *pIn0, unsigned char *pOut0)
+{
+       int k, x, y;
+       unsigned char *pIn, *pOut, *pOutLine;
+       const unsigned int a = frame->rawwidth * frame->rawheight;
+       const unsigned int w = frame->rawwidth / 2;
+
+       /* Copy U and V */
+       pIn = pIn0;
+       pOutLine = pOut0 + a;
+       for (y = 0; y < frame->rawheight - 1; y += 16) {
+               pOut = pOutLine;
+               for (x = 0; x < frame->rawwidth - 1; x += 16) {
+                       make_8x8(pIn, pOut, w);
+                       make_8x8(pIn + 64, pOut + a/4, w);
+                       pIn += 384;
+                       pOut += 8;
+               }
+               pOutLine += 8 * w;
+       }
+
+       /* Copy Y */
+       pIn = pIn0 + 128;
+       pOutLine = pOut0;
+       k = 0;
+       for (y = 0; y < frame->rawheight - 1; y += 8) {
+               pOut = pOutLine;
+               for (x = 0; x < frame->rawwidth - 1; x += 8) {
+                       make_8x8(pIn, pOut, frame->rawwidth);
+                       pIn += 64;
+                       pOut += 8;
+                       if ((++k) > 3) {
+                               k = 0;
+                               pIn += 128;
+                       }
+               }
+               pOutLine += 8 * frame->rawwidth;
+       }
+}
+
+/**********************************************************************
+ *
+ * Decompression
+ *
+ **********************************************************************/
+
+static int
+request_decompressor(struct usb_ov511 *ov)
+{
+       if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
+               err("No decompressor available");
+       } else {
+               err("Unknown bridge");
+       }
+
+       return -ENOSYS;
+}
+
+static void
+decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
+          unsigned char *pIn0, unsigned char *pOut0)
+{
+       if (!ov->decomp_ops)
+               if (request_decompressor(ov))
+                       return;
+
+}
+
+/**********************************************************************
+ *
+ * Format conversion
+ *
+ **********************************************************************/
+
+/* Fuses even and odd fields together, and doubles width.
+ * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
+ * OUTPUT: a normal YUV planar image, with correct aspect ratio
+ */
+static void
+deinterlace(struct ov511_frame *frame, int rawformat,
+           unsigned char *pIn0, unsigned char *pOut0)
+{
+       const int fieldheight = frame->rawheight / 2;
+       const int fieldpix = fieldheight * frame->rawwidth;
+       const int w = frame->width;
+       int x, y;
+       unsigned char *pInEven, *pInOdd, *pOut;
+
+       PDEBUG(5, "fieldheight=%d", fieldheight);
+
+       if (frame->rawheight != frame->height) {
+               err("invalid height");
+               return;
+       }
+
+       if ((frame->rawwidth * 2) != frame->width) {
+               err("invalid width");
+               return;
+       }
+
+       /* Y */
+       pInOdd = pIn0;
+       pInEven = pInOdd + fieldpix;
+       pOut = pOut0;
+       for (y = 0; y < fieldheight; y++) {
+               for (x = 0; x < frame->rawwidth; x++) {
+                       *pOut = *pInEven;
+                       *(pOut+1) = *pInEven++;
+                       *(pOut+w) = *pInOdd;
+                       *(pOut+w+1) = *pInOdd++;
+                       pOut += 2;
+               }
+               pOut += w;
+       }
+
+       if (rawformat == RAWFMT_YUV420) {
+       /* U */
+               pInOdd = pIn0 + fieldpix * 2;
+               pInEven = pInOdd + fieldpix / 4;
+               for (y = 0; y < fieldheight / 2; y++) {
+                       for (x = 0; x < frame->rawwidth / 2; x++) {
+                               *pOut = *pInEven;
+                               *(pOut+1) = *pInEven++;
+                               *(pOut+w/2) = *pInOdd;
+                               *(pOut+w/2+1) = *pInOdd++;
+                               pOut += 2;
+                       }
+                       pOut += w/2;
+               }
+       /* V */
+               pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
+               pInEven = pInOdd + fieldpix / 4;
+               for (y = 0; y < fieldheight / 2; y++) {
+                       for (x = 0; x < frame->rawwidth / 2; x++) {
+                               *pOut = *pInEven;
+                               *(pOut+1) = *pInEven++;
+                               *(pOut+w/2) = *pInOdd;
+                               *(pOut+w/2+1) = *pInOdd++;
+                               pOut += 2;
+                       }
+                       pOut += w/2;
+               }
+       }
+}
+
+static void
+ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+               /* Deinterlace frame, if necessary */
+               if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
+                       if (frame->compressed)
+                               decompress(ov, frame, frame->rawdata,
+                                                frame->tempdata);
+                       else
+                               yuv400raw_to_yuv400p(frame, frame->rawdata,
+                                                    frame->tempdata);
+
+                       deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
+                                   frame->data);
+               } else {
+                       if (frame->compressed)
+                               decompress(ov, frame, frame->rawdata,
+                                                frame->data);
+                       else
+                               yuv400raw_to_yuv400p(frame, frame->rawdata,
+                                                    frame->data);
+               }
+}
+
+/* Process raw YUV420 data into standard YUV420P */
+static void
+ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+       /* Deinterlace frame, if necessary */
+       if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
+               if (frame->compressed)
+                       decompress(ov, frame, frame->rawdata, frame->tempdata);
+               else
+                       yuv420raw_to_yuv420p(frame, frame->rawdata,
+                                            frame->tempdata);
+
+               deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
+                           frame->data);
+       } else {
+               if (frame->compressed)
+                       decompress(ov, frame, frame->rawdata, frame->data);
+               else
+                       yuv420raw_to_yuv420p(frame, frame->rawdata,
+                                            frame->data);
+       }
+}
+
+/* Post-processes the specified frame. This consists of:
+ *     1. Decompress frame, if necessary
+ *     2. Deinterlace frame and scale to proper size, if necessary
+ *     3. Convert from YUV planar to destination format, if necessary
+ *     4. Fix the RGB offset, if necessary
+ */
+static void
+ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+       if (dumppix) {
+               memset(frame->data, 0,
+                       MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+               PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
+               memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
+       } else {
+               switch (frame->format) {
+               case VIDEO_PALETTE_GREY:
+                       ov51x_postprocess_grey(ov, frame);
+                       break;
+               case VIDEO_PALETTE_YUV420:
+               case VIDEO_PALETTE_YUV420P:
+                       ov51x_postprocess_yuv420(ov, frame);
+                       break;
+               default:
+                       err("Cannot convert data to %s",
+                           symbolic(v4l1_plist, frame->format));
+               }
+       }
+}
+
+/**********************************************************************
+ *
+ * OV51x data transfer, IRQ handler
+ *
+ **********************************************************************/
+
+static inline void
+ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
+{
+       int num, offset;
+       int pnum = in[ov->packet_size - 1];             /* Get packet number */
+       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+       struct ov511_frame *frame = &ov->frame[ov->curframe];
+       struct timeval *ts;
+
+       /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+        * byte non-zero. The EOF packet has image width/height in the
+        * 10th and 11th bytes. The 9th byte is given as follows:
+        *
+        * bit 7: EOF
+        *     6: compression enabled
+        *     5: 422/420/400 modes
+        *     4: 422/420/400 modes
+        *     3: 1
+        *     2: snapshot button on
+        *     1: snapshot frame
+        *     0: even/odd field
+        */
+
+       if (printph) {
+               info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
+                    pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+                    in[7], in[8], in[9], in[10], in[11]);
+       }
+
+       /* Check for SOF/EOF packet */
+       if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
+           (~in[8] & 0x08))
+               goto check_middle;
+
+       /* Frame end */
+       if (in[8] & 0x80) {
+               ts = (struct timeval *)(frame->data
+                     + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+               do_gettimeofday(ts);
+
+               /* Get the actual frame size from the EOF header */
+               frame->rawwidth = ((int)(in[9]) + 1) * 8;
+               frame->rawheight = ((int)(in[10]) + 1) * 8;
+
+               PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
+                       ov->curframe, pnum, frame->rawwidth, frame->rawheight,
+                       frame->bytes_recvd);
+
+               /* Validate the header data */
+               RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+               RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
+                                 ov->maxheight);
+
+               /* Don't allow byte count to exceed buffer size */
+               RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+               if (frame->scanstate == STATE_LINES) {
+                       int nextf;
+
+                       frame->grabstate = FRAME_DONE;
+                       wake_up_interruptible(&frame->wq);
+
+                       /* If next frame is ready or grabbing,
+                        * point to it */
+                       nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+                       if (ov->frame[nextf].grabstate == FRAME_READY
+                           || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+                               ov->curframe = nextf;
+                               ov->frame[nextf].scanstate = STATE_SCANNING;
+                       } else {
+                               if (frame->grabstate == FRAME_DONE) {
+                                       PDEBUG(4, "** Frame done **");
+                               } else {
+                                       PDEBUG(4, "Frame not ready? state = %d",
+                                               ov->frame[nextf].grabstate);
+                               }
+
+                               ov->curframe = -1;
+                       }
+               } else {
+                       PDEBUG(5, "Frame done, but not scanning");
+               }
+               /* Image corruption caused by misplaced frame->segment = 0
+                * fixed by carlosf@conectiva.com.br
+                */
+       } else {
+               /* Frame start */
+               PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+
+               /* Check to see if it's a snapshot frame */
+               /* FIXME?? Should the snapshot reset go here? Performance? */
+               if (in[8] & 0x02) {
+                       frame->snapshot = 1;
+                       PDEBUG(3, "snapshot detected");
+               }
+
+               frame->scanstate = STATE_LINES;
+               frame->bytes_recvd = 0;
+               frame->compressed = in[8] & 0x40;
+       }
+
+check_middle:
+       /* Are we in a frame? */
+       if (frame->scanstate != STATE_LINES) {
+               PDEBUG(5, "Not in a frame; packet skipped");
+               return;
+       }
+
+       /* If frame start, skip header */
+       if (frame->bytes_recvd == 0)
+               offset = 9;
+       else
+               offset = 0;
+
+       num = n - offset - 1;
+
+       /* Dump all data exactly as received */
+       if (dumppix == 2) {
+               frame->bytes_recvd += n - 1;
+               if (frame->bytes_recvd <= max_raw)
+                       memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
+                               in, n - 1);
+               else
+                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
+                               frame->bytes_recvd - max_raw);
+       } else if (!frame->compressed && !remove_zeros) {
+               frame->bytes_recvd += num;
+               if (frame->bytes_recvd <= max_raw)
+                       memcpy(frame->rawdata + frame->bytes_recvd - num,
+                               in + offset, num);
+               else
+                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
+                               frame->bytes_recvd - max_raw);
+       } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
+               int b, read = 0, allzero, copied = 0;
+               if (offset) {
+                       frame->bytes_recvd += 32 - offset;      // Bytes out
+                       memcpy(frame->rawdata,  in + offset, 32 - offset);
+                       read += 32;
+               }
+
+               while (read < n - 1) {
+                       allzero = 1;
+                       for (b = 0; b < 32; b++) {
+                               if (in[read + b]) {
+                                       allzero = 0;
+                                       break;
+                               }
+                       }
+
+                       if (allzero) {
+                               /* Don't copy it */
+                       } else {
+                               if (frame->bytes_recvd + copied + 32 <= max_raw)
+                               {
+                                       memcpy(frame->rawdata
+                                               + frame->bytes_recvd + copied,
+                                               in + read, 32);
+                                       copied += 32;
+                               } else {
+                                       PDEBUG(3, "Raw data buffer overrun!!");
+                               }
+                       }
+                       read += 32;
+               }
+
+               frame->bytes_recvd += copied;
+       }
+}
+
+static inline void
+ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
+{
+       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+       struct ov511_frame *frame = &ov->frame[ov->curframe];
+       struct timeval *ts;
+
+       /* Don't copy the packet number byte */
+       if (ov->packet_numbering)
+               --n;
+
+       /* A false positive here is likely, until OVT gives me
+        * the definitive SOF/EOF format */
+       if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
+               if (printph) {
+                       info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
+                            in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+               }
+
+               if (frame->scanstate == STATE_LINES) {
+                       PDEBUG(4, "Detected frame end/start");
+                       goto eof;
+               } else { //scanstate == STATE_SCANNING
+                       /* Frame start */
+                       PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+                       goto sof;
+               }
+       } else {
+               goto check_middle;
+       }
+
+eof:
+       ts = (struct timeval *)(frame->data
+             + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+       do_gettimeofday(ts);
+
+       PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
+               ov->curframe,
+               (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
+
+       // FIXME: Since we don't know the header formats yet,
+       // there is no way to know what the actual image size is
+       frame->rawwidth = frame->width;
+       frame->rawheight = frame->height;
+
+       /* Validate the header data */
+       RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+       RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+
+       /* Don't allow byte count to exceed buffer size */
+       RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+       if (frame->scanstate == STATE_LINES) {
+               int nextf;
+
+               frame->grabstate = FRAME_DONE;
+               wake_up_interruptible(&frame->wq);
+
+               /* If next frame is ready or grabbing,
+                * point to it */
+               nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+               if (ov->frame[nextf].grabstate == FRAME_READY
+                   || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+                       ov->curframe = nextf;
+                       ov->frame[nextf].scanstate = STATE_SCANNING;
+                       frame = &ov->frame[nextf];
+               } else {
+                       if (frame->grabstate == FRAME_DONE) {
+                               PDEBUG(4, "** Frame done **");
+                       } else {
+                               PDEBUG(4, "Frame not ready? state = %d",
+                                      ov->frame[nextf].grabstate);
+                       }
+
+                       ov->curframe = -1;
+                       PDEBUG(4, "SOF dropped (no active frame)");
+                       return;  /* Nowhere to store this frame */
+               }
+       }
+sof:
+       PDEBUG(4, "Starting capture on frame %d", frame->framenum);
+
+// Snapshot not reverse-engineered yet.
+#if 0
+       /* Check to see if it's a snapshot frame */
+       /* FIXME?? Should the snapshot reset go here? Performance? */
+       if (in[8] & 0x02) {
+               frame->snapshot = 1;
+               PDEBUG(3, "snapshot detected");
+       }
+#endif
+       frame->scanstate = STATE_LINES;
+       frame->bytes_recvd = 0;
+       frame->compressed = 1;
+
+check_middle:
+       /* Are we in a frame? */
+       if (frame->scanstate != STATE_LINES) {
+               PDEBUG(4, "scanstate: no SOF yet");
+               return;
+       }
+
+       /* Dump all data exactly as received */
+       if (dumppix == 2) {
+               frame->bytes_recvd += n;
+               if (frame->bytes_recvd <= max_raw)
+                       memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
+               else
+                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
+                               frame->bytes_recvd - max_raw);
+       } else {
+               /* All incoming data are divided into 8-byte segments. If the
+                * segment contains all zero bytes, it must be skipped. These
+                * zero-segments allow the OV518 to mainain a constant data rate
+                * regardless of the effectiveness of the compression. Segments
+                * are aligned relative to the beginning of each isochronous
+                * packet. The first segment in each image is a header (the
+                * decompressor skips it later).
+                */
+
+               int b, read = 0, allzero, copied = 0;
+
+               while (read < n) {
+                       allzero = 1;
+                       for (b = 0; b < 8; b++) {
+                               if (in[read + b]) {
+                                       allzero = 0;
+                                       break;
+                               }
+                       }
+
+                       if (allzero) {
+                       /* Don't copy it */
+                       } else {
+                               if (frame->bytes_recvd + copied + 8 <= max_raw)
+                               {
+                                       memcpy(frame->rawdata
+                                               + frame->bytes_recvd + copied,
+                                               in + read, 8);
+                                       copied += 8;
+                               } else {
+                                       PDEBUG(3, "Raw data buffer overrun!!");
+                               }
+                       }
+                       read += 8;
+               }
+               frame->bytes_recvd += copied;
+       }
+}
+
+static void
+ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+       int i;
+       struct usb_ov511 *ov;
+       struct ov511_sbuf *sbuf;
+
+       if (!urb->context) {
+               PDEBUG(4, "no context");
+               return;
+       }
+
+       sbuf = urb->context;
+       ov = sbuf->ov;
+
+       if (!ov || !ov->dev || !ov->user) {
+               PDEBUG(4, "no device, or not open");
+               return;
+       }
+
+       if (!ov->streaming) {
+               PDEBUG(4, "hmmm... not streaming, but got interrupt");
+               return;
+       }
+
+       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+               PDEBUG(4, "URB unlinked");
+               return;
+       }
+
+       if (urb->status != -EINPROGRESS && urb->status != 0) {
+               err("ERROR: urb->status=%d: %s", urb->status,
+                   symbolic(urb_errlist, urb->status));
+       }
+
+       /* Copy the data received into our frame buffer */
+       PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
+              urb->number_of_packets);
+       for (i = 0; i < urb->number_of_packets; i++) {
+               /* Warning: Don't call *_move_data() if no frame active! */
+               if (ov->curframe >= 0) {
+                       int n = urb->iso_frame_desc[i].actual_length;
+                       int st = urb->iso_frame_desc[i].status;
+                       unsigned char *cdata;
+
+                       urb->iso_frame_desc[i].actual_length = 0;
+                       urb->iso_frame_desc[i].status = 0;
+
+                       cdata = urb->transfer_buffer
+                               + urb->iso_frame_desc[i].offset;
+
+                       if (!n) {
+                               PDEBUG(4, "Zero-length packet");
+                               continue;
+                       }
+
+                       if (st)
+                               PDEBUG(2, "data error: [%d] len=%d, status=%d",
+                                      i, n, st);
+
+                       if (ov->bclass == BCL_OV511)
+                               ov511_move_data(ov, cdata, n);
+                       else if (ov->bclass == BCL_OV518)
+                               ov518_move_data(ov, cdata, n);
+                       else
+                               err("Unknown bridge device (%d)", ov->bridge);
+
+               } else if (waitqueue_active(&ov->wq)) {
+                       wake_up_interruptible(&ov->wq);
+               }
+       }
+
+       /* Resubmit this URB */
+       urb->dev = ov->dev;
+       if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+               err("usb_submit_urb() ret %d", i);
+
+       return;
+}
+
+/****************************************************************************
+ *
+ * Stream initialization and termination
+ *
+ ***************************************************************************/
+
+static int
+ov51x_init_isoc(struct usb_ov511 *ov)
+{
+       struct urb *urb;
+       int fx, err, n, size;
+
+       PDEBUG(3, "*** Initializing capture ***");
+
+       ov->curframe = -1;
+
+       if (ov->bridge == BRG_OV511) {
+               if (cams == 1)
+                       size = 993;
+               else if (cams == 2)
+                       size = 513;
+               else if (cams == 3 || cams == 4)
+                       size = 257;
+               else {
+                       err("\"cams\" parameter too high!");
+                       return -1;
+               }
+       } else if (ov->bridge == BRG_OV511PLUS) {
+               if (cams == 1)
+                       size = 961;
+               else if (cams == 2)
+                       size = 513;
+               else if (cams == 3 || cams == 4)
+                       size = 257;
+               else if (cams >= 5 && cams <= 8)
+                       size = 129;
+               else if (cams >= 9 && cams <= 31)
+                       size = 33;
+               else {
+                       err("\"cams\" parameter too high!");
+                       return -1;
+               }
+       } else if (ov->bclass == BCL_OV518) {
+               if (cams == 1)
+                       size = 896;
+               else if (cams == 2)
+                       size = 512;
+               else if (cams == 3 || cams == 4)
+                       size = 256;
+               else if (cams >= 5 && cams <= 8)
+                       size = 128;
+               else {
+                       err("\"cams\" parameter too high!");
+                       return -1;
+               }
+       } else {
+               err("invalid bridge type");
+               return -1;
+       }
+
+       // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
+       if (ov->bclass == BCL_OV518) {
+               if (packetsize == -1) {
+                       ov518_set_packet_size(ov, 640);
+               } else {
+                       info("Forcing packet size to %d", packetsize);
+                       ov518_set_packet_size(ov, packetsize);
+               }
+       } else {
+               if (packetsize == -1) {
+                       ov511_set_packet_size(ov, size);
+               } else {
+                       info("Forcing packet size to %d", packetsize);
+                       ov511_set_packet_size(ov, packetsize);
+               }
+       }
+
+       for (n = 0; n < OV511_NUMSBUF; n++) {
+               urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+               if (!urb) {
+                       err("init isoc: usb_alloc_urb ret. NULL");
+                       return -ENOMEM;
+               }
+               ov->sbuf[n].urb = urb;
+               urb->dev = ov->dev;
+               urb->context = &ov->sbuf[n];
+               urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = ov->sbuf[n].data;
+               urb->complete = ov51x_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
+               urb->interval = 1;
+               for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+                       urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
+                       urb->iso_frame_desc[fx].length = ov->packet_size;
+               }
+       }
+
+       ov->streaming = 1;
+
+       for (n = 0; n < OV511_NUMSBUF; n++) {
+               ov->sbuf[n].urb->dev = ov->dev;
+               err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
+               if (err) {
+                       err("init isoc: usb_submit_urb(%d) ret %d", n, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static void
+ov51x_unlink_isoc(struct usb_ov511 *ov)
+{
+       int n;
+
+       /* Unschedule all of the iso td's */
+       for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
+               if (ov->sbuf[n].urb) {
+                       usb_kill_urb(ov->sbuf[n].urb);
+                       usb_free_urb(ov->sbuf[n].urb);
+                       ov->sbuf[n].urb = NULL;
+               }
+       }
+}
+
+static void
+ov51x_stop_isoc(struct usb_ov511 *ov)
+{
+       if (!ov->streaming || !ov->dev)
+               return;
+
+       PDEBUG(3, "*** Stopping capture ***");
+
+       if (ov->bclass == BCL_OV518)
+               ov518_set_packet_size(ov, 0);
+       else
+               ov511_set_packet_size(ov, 0);
+
+       ov->streaming = 0;
+
+       ov51x_unlink_isoc(ov);
+}
+
+static int
+ov51x_new_frame(struct usb_ov511 *ov, int framenum)
+{
+       struct ov511_frame *frame;
+       int newnum;
+
+       PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
+
+       if (!ov->dev)
+               return -1;
+
+       /* If we're not grabbing a frame right now and the other frame is */
+       /* ready to be grabbed into, then use it instead */
+       if (ov->curframe == -1) {
+               newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
+               if (ov->frame[newnum].grabstate == FRAME_READY)
+                       framenum = newnum;
+       } else
+               return 0;
+
+       frame = &ov->frame[framenum];
+
+       PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
+              frame->width, frame->height);
+
+       frame->grabstate = FRAME_GRABBING;
+       frame->scanstate = STATE_SCANNING;
+       frame->snapshot = 0;
+
+       ov->curframe = framenum;
+
+       /* Make sure it's not too big */
+       if (frame->width > ov->maxwidth)
+               frame->width = ov->maxwidth;
+
+       frame->width &= ~7L;            /* Multiple of 8 */
+
+       if (frame->height > ov->maxheight)
+               frame->height = ov->maxheight;
+
+       frame->height &= ~3L;           /* Multiple of 4 */
+
+       return 0;
+}
+
+/****************************************************************************
+ *
+ * Buffer management
+ *
+ ***************************************************************************/
+
+/*
+ * - You must acquire buf_lock before entering this function.
+ * - Because this code will free any non-null pointer, you must be sure to null
+ *   them if you explicitly free them somewhere else!
+ */
+static void
+ov51x_do_dealloc(struct usb_ov511 *ov)
+{
+       int i;
+       PDEBUG(4, "entered");
+
+       if (ov->fbuf) {
+               rvfree(ov->fbuf, OV511_NUMFRAMES
+                      * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+               ov->fbuf = NULL;
+       }
+
+       vfree(ov->rawfbuf);
+       ov->rawfbuf = NULL;
+
+       vfree(ov->tempfbuf);
+       ov->tempfbuf = NULL;
+
+       for (i = 0; i < OV511_NUMSBUF; i++) {
+               kfree(ov->sbuf[i].data);
+               ov->sbuf[i].data = NULL;
+       }
+
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].data = NULL;
+               ov->frame[i].rawdata = NULL;
+               ov->frame[i].tempdata = NULL;
+               if (ov->frame[i].compbuf) {
+                       free_page((unsigned long) ov->frame[i].compbuf);
+                       ov->frame[i].compbuf = NULL;
+               }
+       }
+
+       PDEBUG(4, "buffer memory deallocated");
+       ov->buf_state = BUF_NOT_ALLOCATED;
+       PDEBUG(4, "leaving");
+}
+
+static int
+ov51x_alloc(struct usb_ov511 *ov)
+{
+       int i;
+       const int w = ov->maxwidth;
+       const int h = ov->maxheight;
+       const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
+       const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
+
+       PDEBUG(4, "entered");
+       mutex_lock(&ov->buf_lock);
+
+       if (ov->buf_state == BUF_ALLOCATED)
+               goto out;
+
+       ov->fbuf = rvmalloc(data_bufsize);
+       if (!ov->fbuf)
+               goto error;
+
+       ov->rawfbuf = vmalloc(raw_bufsize);
+       if (!ov->rawfbuf)
+               goto error;
+
+       memset(ov->rawfbuf, 0, raw_bufsize);
+
+       ov->tempfbuf = vmalloc(raw_bufsize);
+       if (!ov->tempfbuf)
+               goto error;
+
+       memset(ov->tempfbuf, 0, raw_bufsize);
+
+       for (i = 0; i < OV511_NUMSBUF; i++) {
+               ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+                       MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+               if (!ov->sbuf[i].data)
+                       goto error;
+
+               PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
+       }
+
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
+               ov->frame[i].rawdata = ov->rawfbuf
+                + i * MAX_RAW_DATA_SIZE(w, h);
+               ov->frame[i].tempdata = ov->tempfbuf
+                + i * MAX_RAW_DATA_SIZE(w, h);
+
+               ov->frame[i].compbuf =
+                (unsigned char *) __get_free_page(GFP_KERNEL);
+               if (!ov->frame[i].compbuf)
+                       goto error;
+
+               PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
+       }
+
+       ov->buf_state = BUF_ALLOCATED;
+out:
+       mutex_unlock(&ov->buf_lock);
+       PDEBUG(4, "leaving");
+       return 0;
+error:
+       ov51x_do_dealloc(ov);
+       mutex_unlock(&ov->buf_lock);
+       PDEBUG(4, "errored");
+       return -ENOMEM;
+}
+
+static void
+ov51x_dealloc(struct usb_ov511 *ov)
+{
+       PDEBUG(4, "entered");
+       mutex_lock(&ov->buf_lock);
+       ov51x_do_dealloc(ov);
+       mutex_unlock(&ov->buf_lock);
+       PDEBUG(4, "leaving");
+}
+
+/****************************************************************************
+ *
+ * V4L 1 API
+ *
+ ***************************************************************************/
+
+static int
+ov51x_v4l1_open(struct inode *inode, struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       int err, i;
+
+       PDEBUG(4, "opening");
+
+       mutex_lock(&ov->lock);
+
+       err = -EBUSY;
+       if (ov->user)
+               goto out;
+
+       ov->sub_flag = 0;
+
+       /* In case app doesn't set them... */
+       err = ov51x_set_default_params(ov);
+       if (err < 0)
+               goto out;
+
+       /* Make sure frames are reset */
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].grabstate = FRAME_UNUSED;
+               ov->frame[i].bytes_read = 0;
+       }
+
+       /* If compression is on, make sure now that a
+        * decompressor can be loaded */
+       if (ov->compress && !ov->decomp_ops) {
+               err = request_decompressor(ov);
+               if (err && !dumppix)
+                       goto out;
+       }
+
+       err = ov51x_alloc(ov);
+       if (err < 0)
+               goto out;
+
+       err = ov51x_init_isoc(ov);
+       if (err) {
+               ov51x_dealloc(ov);
+               goto out;
+       }
+
+       ov->user++;
+       file->private_data = vdev;
+
+       if (ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 1);
+
+out:
+       mutex_unlock(&ov->lock);
+       return err;
+}
+
+static int
+ov51x_v4l1_close(struct inode *inode, struct file *file)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+
+       PDEBUG(4, "ov511_close");
+
+       mutex_lock(&ov->lock);
+
+       ov->user--;
+       ov51x_stop_isoc(ov);
+
+       if (ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 0);
+
+       if (ov->dev)
+               ov51x_dealloc(ov);
+
+       mutex_unlock(&ov->lock);
+
+       /* Device unplugged while open. Only a minimum of unregistration is done
+        * here; the disconnect callback already did the rest. */
+       if (!ov->dev) {
+               mutex_lock(&ov->cbuf_lock);
+               kfree(ov->cbuf);
+               ov->cbuf = NULL;
+               mutex_unlock(&ov->cbuf_lock);
+
+               ov51x_dealloc(ov);
+               kfree(ov);
+               ov = NULL;
+       }
+
+       file->private_data = NULL;
+       return 0;
+}
+
+/* Do not call this function directly! */
+static int
+ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
+                         unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       PDEBUG(5, "IOCtl: 0x%X", cmd);
+
+       if (!ov->dev)
+               return -EIO;
+
+       switch (cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability *b = arg;
+
+               PDEBUG(4, "VIDIOCGCAP");
+
+               memset(b, 0, sizeof(struct video_capability));
+               sprintf(b->name, "%s USB Camera",
+                       symbolic(brglist, ov->bridge));
+               b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+               b->channels = ov->num_inputs;
+               b->audios = 0;
+               b->maxwidth = ov->maxwidth;
+               b->maxheight = ov->maxheight;
+               b->minwidth = ov->minwidth;
+               b->minheight = ov->minheight;
+
+               return 0;
+       }
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *v = arg;
+
+               PDEBUG(4, "VIDIOCGCHAN");
+
+               if ((unsigned)(v->channel) >= ov->num_inputs) {
+                       err("Invalid channel (%d)", v->channel);
+                       return -EINVAL;
+               }
+
+               v->norm = ov->norm;
+               v->type = VIDEO_TYPE_CAMERA;
+               v->flags = 0;
+//             v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
+               v->tuners = 0;
+               decoder_get_input_name(ov, v->channel, v->name);
+
+               return 0;
+       }
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *v = arg;
+               int err;
+
+               PDEBUG(4, "VIDIOCSCHAN");
+
+               /* Make sure it's not a camera */
+               if (!ov->has_decoder) {
+                       if (v->channel == 0)
+                               return 0;
+                       else
+                               return -EINVAL;
+               }
+
+               if (v->norm != VIDEO_MODE_PAL &&
+                   v->norm != VIDEO_MODE_NTSC &&
+                   v->norm != VIDEO_MODE_SECAM &&
+                   v->norm != VIDEO_MODE_AUTO) {
+                       err("Invalid norm (%d)", v->norm);
+                       return -EINVAL;
+               }
+
+               if ((unsigned)(v->channel) >= ov->num_inputs) {
+                       err("Invalid channel (%d)", v->channel);
+                       return -EINVAL;
+               }
+
+               err = decoder_set_input(ov, v->channel);
+               if (err)
+                       return err;
+
+               err = decoder_set_norm(ov, v->norm);
+               if (err)
+                       return err;
+
+               return 0;
+       }
+       case VIDIOCGPICT:
+       {
+               struct video_picture *p = arg;
+
+               PDEBUG(4, "VIDIOCGPICT");
+
+               memset(p, 0, sizeof(struct video_picture));
+               if (sensor_get_picture(ov, p))
+                       return -EIO;
+
+               /* Can we get these from frame[0]? -claudio? */
+               p->depth = ov->frame[0].depth;
+               p->palette = ov->frame[0].format;
+
+               return 0;
+       }
+       case VIDIOCSPICT:
+       {
+               struct video_picture *p = arg;
+               int i, rc;
+
+               PDEBUG(4, "VIDIOCSPICT");
+
+               if (!get_depth(p->palette))
+                       return -EINVAL;
+
+               if (sensor_set_picture(ov, p))
+                       return -EIO;
+
+               if (force_palette && p->palette != force_palette) {
+                       info("Palette rejected (%s)",
+                            symbolic(v4l1_plist, p->palette));
+                       return -EINVAL;
+               }
+
+               // FIXME: Format should be independent of frames
+               if (p->palette != ov->frame[0].format) {
+                       PDEBUG(4, "Detected format change");
+
+                       rc = ov51x_wait_frames_inactive(ov);
+                       if (rc)
+                               return rc;
+
+                       mode_init_regs(ov, ov->frame[0].width,
+                               ov->frame[0].height, p->palette, ov->sub_flag);
+               }
+
+               PDEBUG(4, "Setting depth=%d, palette=%s",
+                      p->depth, symbolic(v4l1_plist, p->palette));
+
+               for (i = 0; i < OV511_NUMFRAMES; i++) {
+                       ov->frame[i].depth = p->depth;
+                       ov->frame[i].format = p->palette;
+               }
+
+               return 0;
+       }
+       case VIDIOCGCAPTURE:
+       {
+               int *vf = arg;
+
+               PDEBUG(4, "VIDIOCGCAPTURE");
+
+               ov->sub_flag = *vf;
+               return 0;
+       }
+       case VIDIOCSCAPTURE:
+       {
+               struct video_capture *vc = arg;
+
+               PDEBUG(4, "VIDIOCSCAPTURE");
+
+               if (vc->flags)
+                       return -EINVAL;
+               if (vc->decimation)
+                       return -EINVAL;
+
+               vc->x &= ~3L;
+               vc->y &= ~1L;
+               vc->y &= ~31L;
+
+               if (vc->width == 0)
+                       vc->width = 32;
+
+               vc->height /= 16;
+               vc->height *= 16;
+               if (vc->height == 0)
+                       vc->height = 16;
+
+               ov->subx = vc->x;
+               ov->suby = vc->y;
+               ov->subw = vc->width;
+               ov->subh = vc->height;
+
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window *vw = arg;
+               int i, rc;
+
+               PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
+
+#if 0
+               if (vw->flags)
+                       return -EINVAL;
+               if (vw->clipcount)
+                       return -EINVAL;
+               if (vw->height != ov->maxheight)
+                       return -EINVAL;
+               if (vw->width != ov->maxwidth)
+                       return -EINVAL;
+#endif
+
+               rc = ov51x_wait_frames_inactive(ov);
+               if (rc)
+                       return rc;
+
+               rc = mode_init_regs(ov, vw->width, vw->height,
+                       ov->frame[0].format, ov->sub_flag);
+               if (rc < 0)
+                       return rc;
+
+               for (i = 0; i < OV511_NUMFRAMES; i++) {
+                       ov->frame[i].width = vw->width;
+                       ov->frame[i].height = vw->height;
+               }
+
+               return 0;
+       }
+       case VIDIOCGWIN:
+       {
+               struct video_window *vw = arg;
+
+               memset(vw, 0, sizeof(struct video_window));
+               vw->x = 0;              /* FIXME */
+               vw->y = 0;
+               vw->width = ov->frame[0].width;
+               vw->height = ov->frame[0].height;
+               vw->flags = 30;
+
+               PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
+
+               return 0;
+       }
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *vm = arg;
+               int i;
+
+               PDEBUG(4, "VIDIOCGMBUF");
+
+               memset(vm, 0, sizeof(struct video_mbuf));
+               vm->size = OV511_NUMFRAMES
+                          * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+               vm->frames = OV511_NUMFRAMES;
+
+               vm->offsets[0] = 0;
+               for (i = 1; i < OV511_NUMFRAMES; i++) {
+                       vm->offsets[i] = vm->offsets[i-1]
+                          + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+               }
+
+               return 0;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *vm = arg;
+               int rc, depth;
+               unsigned int f = vm->frame;
+
+               PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
+                       vm->height, symbolic(v4l1_plist, vm->format));
+
+               depth = get_depth(vm->format);
+               if (!depth) {
+                       PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
+                              symbolic(v4l1_plist, vm->format));
+                       return -EINVAL;
+               }
+
+               if (f >= OV511_NUMFRAMES) {
+                       err("VIDIOCMCAPTURE: invalid frame (%d)", f);
+                       return -EINVAL;
+               }
+
+               if (vm->width > ov->maxwidth
+                   || vm->height > ov->maxheight) {
+                       err("VIDIOCMCAPTURE: requested dimensions too big");
+                       return -EINVAL;
+               }
+
+               if (ov->frame[f].grabstate == FRAME_GRABBING) {
+                       PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
+                       return -EBUSY;
+               }
+
+               if (force_palette && (vm->format != force_palette)) {
+                       PDEBUG(2, "palette rejected (%s)",
+                              symbolic(v4l1_plist, vm->format));
+                       return -EINVAL;
+               }
+
+               if ((ov->frame[f].width != vm->width) ||
+                   (ov->frame[f].height != vm->height) ||
+                   (ov->frame[f].format != vm->format) ||
+                   (ov->frame[f].sub_flag != ov->sub_flag) ||
+                   (ov->frame[f].depth != depth)) {
+                       PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
+
+                       rc = ov51x_wait_frames_inactive(ov);
+                       if (rc)
+                               return rc;
+
+                       rc = mode_init_regs(ov, vm->width, vm->height,
+                               vm->format, ov->sub_flag);
+#if 0
+                       if (rc < 0) {
+                               PDEBUG(1, "Got error while initializing regs ");
+                               return ret;
+                       }
+#endif
+                       ov->frame[f].width = vm->width;
+                       ov->frame[f].height = vm->height;
+                       ov->frame[f].format = vm->format;
+                       ov->frame[f].sub_flag = ov->sub_flag;
+                       ov->frame[f].depth = depth;
+               }
+
+               /* Mark it as ready */
+               ov->frame[f].grabstate = FRAME_READY;
+
+               PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
+
+               return ov51x_new_frame(ov, f);
+       }
+       case VIDIOCSYNC:
+       {
+               unsigned int fnum = *((unsigned int *) arg);
+               struct ov511_frame *frame;
+               int rc;
+
+               if (fnum >= OV511_NUMFRAMES) {
+                       err("VIDIOCSYNC: invalid frame (%d)", fnum);
+                       return -EINVAL;
+               }
+
+               frame = &ov->frame[fnum];
+
+               PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
+                      frame->grabstate);
+
+               switch (frame->grabstate) {
+               case FRAME_UNUSED:
+                       return -EINVAL;
+               case FRAME_READY:
+               case FRAME_GRABBING:
+               case FRAME_ERROR:
+redo:
+                       if (!ov->dev)
+                               return -EIO;
+
+                       rc = wait_event_interruptible(frame->wq,
+                           (frame->grabstate == FRAME_DONE)
+                           || (frame->grabstate == FRAME_ERROR));
+
+                       if (rc)
+                               return rc;
+
+                       if (frame->grabstate == FRAME_ERROR) {
+                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
+                                       return rc;
+                               goto redo;
+                       }
+                       /* Fall through */
+               case FRAME_DONE:
+                       if (ov->snap_enabled && !frame->snapshot) {
+                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
+                                       return rc;
+                               goto redo;
+                       }
+
+                       frame->grabstate = FRAME_UNUSED;
+
+                       /* Reset the hardware snapshot button */
+                       /* FIXME - Is this the best place for this? */
+                       if ((ov->snap_enabled) && (frame->snapshot)) {
+                               frame->snapshot = 0;
+                               ov51x_clear_snapshot(ov);
+                       }
+
+                       /* Decompression, format conversion, etc... */
+                       ov51x_postprocess(ov, frame);
+
+                       break;
+               } /* end switch */
+
+               return 0;
+       }
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer *vb = arg;
+
+               PDEBUG(4, "VIDIOCGFBUF");
+
+               memset(vb, 0, sizeof(struct video_buffer));
+
+               return 0;
+       }
+       case VIDIOCGUNIT:
+       {
+               struct video_unit *vu = arg;
+
+               PDEBUG(4, "VIDIOCGUNIT");
+
+               memset(vu, 0, sizeof(struct video_unit));
+
+               vu->video = ov->vdev->minor;
+               vu->vbi = VIDEO_NO_UNIT;
+               vu->radio = VIDEO_NO_UNIT;
+               vu->audio = VIDEO_NO_UNIT;
+               vu->teletext = VIDEO_NO_UNIT;
+
+               return 0;
+       }
+       case OV511IOC_WI2C:
+       {
+               struct ov511_i2c_struct *w = arg;
+
+               return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
+       }
+       case OV511IOC_RI2C:
+       {
+               struct ov511_i2c_struct *r = arg;
+               int rc;
+
+               rc = i2c_r_slave(ov, r->slave, r->reg);
+               if (rc < 0)
+                       return rc;
+
+               r->value = rc;
+               return 0;
+       }
+       default:
+               PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
+               return -ENOIOCTLCMD;
+       } /* end switch */
+
+       return 0;
+}
+
+static int
+ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
+                unsigned int cmd, unsigned long arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       int rc;
+
+       if (mutex_lock_interruptible(&ov->lock))
+               return -EINTR;
+
+       rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
+
+       mutex_unlock(&ov->lock);
+       return rc;
+}
+
+static ssize_t
+ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
+{
+       struct video_device *vdev = file->private_data;
+       int noblock = file->f_flags&O_NONBLOCK;
+       unsigned long count = cnt;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       int i, rc = 0, frmx = -1;
+       struct ov511_frame *frame;
+
+       if (mutex_lock_interruptible(&ov->lock))
+               return -EINTR;
+
+       PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
+
+       if (!vdev || !buf) {
+               rc = -EFAULT;
+               goto error;
+       }
+
+       if (!ov->dev) {
+               rc = -EIO;
+               goto error;
+       }
+
+// FIXME: Only supports two frames
+       /* See if a frame is completed, then use it. */
+       if (ov->frame[0].grabstate >= FRAME_DONE)       /* _DONE or _ERROR */
+               frmx = 0;
+       else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
+               frmx = 1;
+
+       /* If nonblocking we return immediately */
+       if (noblock && (frmx == -1)) {
+               rc = -EAGAIN;
+               goto error;
+       }
+
+       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
+       /* See if a frame is in process (grabbing), then use it. */
+       if (frmx == -1) {
+               if (ov->frame[0].grabstate == FRAME_GRABBING)
+                       frmx = 0;
+               else if (ov->frame[1].grabstate == FRAME_GRABBING)
+                       frmx = 1;
+       }
+
+       /* If no frame is active, start one. */
+       if (frmx == -1) {
+               if ((rc = ov51x_new_frame(ov, frmx = 0))) {
+                       err("read: ov51x_new_frame error");
+                       goto error;
+               }
+       }
+
+       frame = &ov->frame[frmx];
+
+restart:
+       if (!ov->dev) {
+               rc = -EIO;
+               goto error;
+       }
+
+       /* Wait while we're grabbing the image */
+       PDEBUG(4, "Waiting image grabbing");
+       rc = wait_event_interruptible(frame->wq,
+               (frame->grabstate == FRAME_DONE)
+               || (frame->grabstate == FRAME_ERROR));
+
+       if (rc)
+               goto error;
+
+       PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
+       PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
+
+       if (frame->grabstate == FRAME_ERROR) {
+               frame->bytes_read = 0;
+               err("** ick! ** Errored frame %d", ov->curframe);
+               if (ov51x_new_frame(ov, frmx)) {
+                       err("read: ov51x_new_frame error");
+                       goto error;
+               }
+               goto restart;
+       }
+
+
+       /* Repeat until we get a snapshot frame */
+       if (ov->snap_enabled)
+               PDEBUG(4, "Waiting snapshot frame");
+       if (ov->snap_enabled && !frame->snapshot) {
+               frame->bytes_read = 0;
+               if ((rc = ov51x_new_frame(ov, frmx))) {
+                       err("read: ov51x_new_frame error");
+                       goto error;
+               }
+               goto restart;
+       }
+
+       /* Clear the snapshot */
+       if (ov->snap_enabled && frame->snapshot) {
+               frame->snapshot = 0;
+               ov51x_clear_snapshot(ov);
+       }
+
+       /* Decompression, format conversion, etc... */
+       ov51x_postprocess(ov, frame);
+
+       PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
+               frame->bytes_read,
+               get_frame_length(frame));
+
+       /* copy bytes to user space; we allow for partials reads */
+//     if ((count + frame->bytes_read)
+//         > get_frame_length((struct ov511_frame *)frame))
+//             count = frame->scanlength - frame->bytes_read;
+
+       /* FIXME - count hardwired to be one frame... */
+       count = get_frame_length(frame);
+
+       PDEBUG(4, "Copy to user space: %ld bytes", count);
+       if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
+               PDEBUG(4, "Copy failed! %d bytes not copied", i);
+               rc = -EFAULT;
+               goto error;
+       }
+
+       frame->bytes_read += count;
+       PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
+               count, frame->bytes_read);
+
+       /* If all data have been read... */
+       if (frame->bytes_read
+           >= get_frame_length(frame)) {
+               frame->bytes_read = 0;
+
+// FIXME: Only supports two frames
+               /* Mark it as available to be used again. */
+               ov->frame[frmx].grabstate = FRAME_UNUSED;
+               if ((rc = ov51x_new_frame(ov, !frmx))) {
+                       err("ov51x_new_frame returned error");
+                       goto error;
+               }
+       }
+
+       PDEBUG(4, "read finished, returning %ld (sweet)", count);
+
+       mutex_unlock(&ov->lock);
+       return count;
+
+error:
+       mutex_unlock(&ov->lock);
+       return rc;
+}
+
+static int
+ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = file->private_data;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end - vma->vm_start;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       unsigned long page, pos;
+
+       if (ov->dev == NULL)
+               return -EIO;
+
+       PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
+
+       if (size > (((OV511_NUMFRAMES
+                     * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
+                     + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&ov->lock))
+               return -EINTR;
+
+       pos = (unsigned long)ov->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       mutex_unlock(&ov->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       mutex_unlock(&ov->lock);
+       return 0;
+}
+
+static struct file_operations ov511_fops = {
+       .owner =        THIS_MODULE,
+       .open =         ov51x_v4l1_open,
+       .release =      ov51x_v4l1_close,
+       .read =         ov51x_v4l1_read,
+       .mmap =         ov51x_v4l1_mmap,
+       .ioctl =        ov51x_v4l1_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+
+static struct video_device vdev_template = {
+       .owner =        THIS_MODULE,
+       .name =         "OV511 USB Camera",
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_OV511,
+       .fops =         &ov511_fops,
+       .release =      video_device_release,
+       .minor =        -1,
+};
+
+/****************************************************************************
+ *
+ * OV511 and sensor configuration
+ *
+ ***************************************************************************/
+
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
+ * the same register settings as the OV7610, since they are very similar.
+ */
+static int
+ov7xx0_configure(struct usb_ov511 *ov)
+{
+       int i, success;
+       int rc;
+
+       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
+        *
+        * Register 0x0f in the 7610 has the following effects:
+        *
+        * 0x85 (AEC method 1): Best overall, good contrast range
+        * 0x45 (AEC method 2): Very overexposed
+        * 0xa5 (spec sheet default): Ok, but the black level is
+        *      shifted resulting in loss of contrast
+        * 0x05 (old driver setting): very overexposed, too much
+        *      contrast
+        */
+       static struct ov511_regvals aRegvalsNorm7610[] = {
+               { OV511_I2C_BUS, 0x10, 0xff },
+               { OV511_I2C_BUS, 0x16, 0x06 },
+               { OV511_I2C_BUS, 0x28, 0x24 },
+               { OV511_I2C_BUS, 0x2b, 0xac },
+               { OV511_I2C_BUS, 0x12, 0x00 },
+               { OV511_I2C_BUS, 0x38, 0x81 },
+               { OV511_I2C_BUS, 0x28, 0x24 },  /* 0c */
+               { OV511_I2C_BUS, 0x0f, 0x85 },  /* lg's setting */
+               { OV511_I2C_BUS, 0x15, 0x01 },
+               { OV511_I2C_BUS, 0x20, 0x1c },
+               { OV511_I2C_BUS, 0x23, 0x2a },
+               { OV511_I2C_BUS, 0x24, 0x10 },
+               { OV511_I2C_BUS, 0x25, 0x8a },
+               { OV511_I2C_BUS, 0x26, 0xa2 },
+               { OV511_I2C_BUS, 0x27, 0xc2 },
+               { OV511_I2C_BUS, 0x2a, 0x04 },
+               { OV511_I2C_BUS, 0x2c, 0xfe },
+               { OV511_I2C_BUS, 0x2d, 0x93 },
+               { OV511_I2C_BUS, 0x30, 0x71 },
+               { OV511_I2C_BUS, 0x31, 0x60 },
+               { OV511_I2C_BUS, 0x32, 0x26 },
+               { OV511_I2C_BUS, 0x33, 0x20 },
+               { OV511_I2C_BUS, 0x34, 0x48 },
+               { OV511_I2C_BUS, 0x12, 0x24 },
+               { OV511_I2C_BUS, 0x11, 0x01 },
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0d, 0x24 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       static struct ov511_regvals aRegvalsNorm7620[] = {
+               { OV511_I2C_BUS, 0x00, 0x00 },
+               { OV511_I2C_BUS, 0x01, 0x80 },
+               { OV511_I2C_BUS, 0x02, 0x80 },
+               { OV511_I2C_BUS, 0x03, 0xc0 },
+               { OV511_I2C_BUS, 0x06, 0x60 },
+               { OV511_I2C_BUS, 0x07, 0x00 },
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0d, 0x24 },
+               { OV511_I2C_BUS, 0x11, 0x01 },
+               { OV511_I2C_BUS, 0x12, 0x24 },
+               { OV511_I2C_BUS, 0x13, 0x01 },
+               { OV511_I2C_BUS, 0x14, 0x84 },
+               { OV511_I2C_BUS, 0x15, 0x01 },
+               { OV511_I2C_BUS, 0x16, 0x03 },
+               { OV511_I2C_BUS, 0x17, 0x2f },
+               { OV511_I2C_BUS, 0x18, 0xcf },
+               { OV511_I2C_BUS, 0x19, 0x06 },
+               { OV511_I2C_BUS, 0x1a, 0xf5 },
+               { OV511_I2C_BUS, 0x1b, 0x00 },
+               { OV511_I2C_BUS, 0x20, 0x18 },
+               { OV511_I2C_BUS, 0x21, 0x80 },
+               { OV511_I2C_BUS, 0x22, 0x80 },
+               { OV511_I2C_BUS, 0x23, 0x00 },
+               { OV511_I2C_BUS, 0x26, 0xa2 },
+               { OV511_I2C_BUS, 0x27, 0xea },
+               { OV511_I2C_BUS, 0x28, 0x20 },
+               { OV511_I2C_BUS, 0x29, 0x00 },
+               { OV511_I2C_BUS, 0x2a, 0x10 },
+               { OV511_I2C_BUS, 0x2b, 0x00 },
+               { OV511_I2C_BUS, 0x2c, 0x88 },
+               { OV511_I2C_BUS, 0x2d, 0x91 },
+               { OV511_I2C_BUS, 0x2e, 0x80 },
+               { OV511_I2C_BUS, 0x2f, 0x44 },
+               { OV511_I2C_BUS, 0x60, 0x27 },
+               { OV511_I2C_BUS, 0x61, 0x02 },
+               { OV511_I2C_BUS, 0x62, 0x5f },
+               { OV511_I2C_BUS, 0x63, 0xd5 },
+               { OV511_I2C_BUS, 0x64, 0x57 },
+               { OV511_I2C_BUS, 0x65, 0x83 },
+               { OV511_I2C_BUS, 0x66, 0x55 },
+               { OV511_I2C_BUS, 0x67, 0x92 },
+               { OV511_I2C_BUS, 0x68, 0xcf },
+               { OV511_I2C_BUS, 0x69, 0x76 },
+               { OV511_I2C_BUS, 0x6a, 0x22 },
+               { OV511_I2C_BUS, 0x6b, 0x00 },
+               { OV511_I2C_BUS, 0x6c, 0x02 },
+               { OV511_I2C_BUS, 0x6d, 0x44 },
+               { OV511_I2C_BUS, 0x6e, 0x80 },
+               { OV511_I2C_BUS, 0x6f, 0x1d },
+               { OV511_I2C_BUS, 0x70, 0x8b },
+               { OV511_I2C_BUS, 0x71, 0x00 },
+               { OV511_I2C_BUS, 0x72, 0x14 },
+               { OV511_I2C_BUS, 0x73, 0x54 },
+               { OV511_I2C_BUS, 0x74, 0x00 },
+               { OV511_I2C_BUS, 0x75, 0x8e },
+               { OV511_I2C_BUS, 0x76, 0x00 },
+               { OV511_I2C_BUS, 0x77, 0xff },
+               { OV511_I2C_BUS, 0x78, 0x80 },
+               { OV511_I2C_BUS, 0x79, 0x80 },
+               { OV511_I2C_BUS, 0x7a, 0x80 },
+               { OV511_I2C_BUS, 0x7b, 0xe2 },
+               { OV511_I2C_BUS, 0x7c, 0x00 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       PDEBUG(4, "starting configuration");
+
+       /* This looks redundant, but is necessary for WebCam 3 */
+       ov->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
+               return -1;
+
+       if (init_ov_sensor(ov) >= 0) {
+               PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
+       } else {
+               /* Reset the 76xx */
+               if (i2c_w(ov, 0x12, 0x80) < 0)
+                       return -1;
+
+               /* Wait for it to initialize */
+               msleep(150);
+
+               i = 0;
+               success = 0;
+               while (i <= i2c_detect_tries) {
+                       if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
+                           (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
+                               success = 1;
+                               break;
+                       } else {
+                               i++;
+                       }
+               }
+
+// Was (i == i2c_detect_tries) previously. This obviously used to always report
+// success. Whether anyone actually depended on that bug is unknown
+               if ((i >= i2c_detect_tries) && (success == 0)) {
+                       err("Failed to read sensor ID. You might not have an");
+                       err("OV7610/20, or it may be not responding. Report");
+                       err("this to " EMAIL);
+                       err("This is only a warning. You can attempt to use");
+                       err("your camera anyway");
+// Only issue a warning for now
+//                     return -1;
+               } else {
+                       PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
+               }
+       }
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(ov, OV7610_REG_COM_I);
+
+       if (rc < 0) {
+               err("Error detecting sensor type");
+               return -1;
+       } else if ((rc & 3) == 3) {
+               info("Sensor is an OV7610");
+               ov->sensor = SEN_OV7610;
+       } else if ((rc & 3) == 1) {
+               /* I don't know what's different about the 76BE yet. */
+               if (i2c_r(ov, 0x15) & 1)
+                       info("Sensor is an OV7620AE");
+               else
+                       info("Sensor is an OV76BE");
+
+               /* OV511+ will return all zero isoc data unless we
+                * configure the sensor as a 7620. Someone needs to
+                * find the exact reg. setting that causes this. */
+               if (ov->bridge == BRG_OV511PLUS) {
+                       info("Enabling 511+/7620AE workaround");
+                       ov->sensor = SEN_OV7620;
+               } else {
+                       ov->sensor = SEN_OV76BE;
+               }
+       } else if ((rc & 3) == 0) {
+               info("Sensor is an OV7620");
+               ov->sensor = SEN_OV7620;
+       } else {
+               err("Unknown image sensor version: %d", rc & 3);
+               return -1;
+       }
+
+       if (ov->sensor == SEN_OV7620) {
+               PDEBUG(4, "Writing 7620 registers");
+               if (write_regvals(ov, aRegvalsNorm7620))
+                       return -1;
+       } else {
+               PDEBUG(4, "Writing 7610 registers");
+               if (write_regvals(ov, aRegvalsNorm7610))
+                       return -1;
+       }
+
+       /* Set sensor-specific vars */
+       ov->maxwidth = 640;
+       ov->maxheight = 480;
+       ov->minwidth = 64;
+       ov->minheight = 48;
+
+       // FIXME: These do not match the actual settings yet
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x80 << 8;
+       ov->colour = 0x80 << 8;
+       ov->hue = 0x80 << 8;
+
+       return 0;
+}
+
+/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
+static int
+ov6xx0_configure(struct usb_ov511 *ov)
+{
+       int rc;
+
+       static struct ov511_regvals aRegvalsNorm6x20[] = {
+               { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
+               { OV511_I2C_BUS, 0x11, 0x01 },
+               { OV511_I2C_BUS, 0x03, 0x60 },
+               { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
+               { OV511_I2C_BUS, 0x07, 0xa8 },
+               /* The ratio of 0x0c and 0x0d  controls the white point */
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0d, 0x24 },
+               { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
+               { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
+               { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
+               { OV511_I2C_BUS, 0x14, 0x04 },
+               /* 0x16: 0x06 helps frame stability with moving objects */
+               { OV511_I2C_BUS, 0x16, 0x06 },
+//             { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+               { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+               /* 0x28: 0x05 Selects RGB format if RGB on */
+               { OV511_I2C_BUS, 0x28, 0x05 },
+               { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//             { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
+               { OV511_I2C_BUS, 0x2d, 0x99 },
+               { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
+               { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
+               { OV511_I2C_BUS, 0x38, 0x8b },
+               { OV511_I2C_BUS, 0x39, 0x40 },
+
+               { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
+               { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
+               { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+               { OV511_I2C_BUS, 0x3d, 0x80 },
+               /* These next two registers (0x4a, 0x4b) are undocumented. They
+                * control the color balance */
+               { OV511_I2C_BUS, 0x4a, 0x80 },
+               { OV511_I2C_BUS, 0x4b, 0x80 },
+               { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
+               { OV511_I2C_BUS, 0x4e, 0xc1 },
+               { OV511_I2C_BUS, 0x4f, 0x04 },
+// Do 50-53 have any effect?
+// Toggle 0x12[2] off and on here?
+               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
+       };
+
+       static struct ov511_regvals aRegvalsNorm6x30[] = {
+       /*OK*/  { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
+               { OV511_I2C_BUS, 0x11, 0x00 },
+       /*OK*/  { OV511_I2C_BUS, 0x03, 0x60 },
+       /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
+               { OV511_I2C_BUS, 0x07, 0xa8 },
+               /* The ratio of 0x0c and 0x0d  controls the white point */
+       /*OK*/  { OV511_I2C_BUS, 0x0c, 0x24 },
+       /*OK*/  { OV511_I2C_BUS, 0x0d, 0x24 },
+       /*A*/   { OV511_I2C_BUS, 0x0e, 0x20 },
+//     /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
+               { OV511_I2C_BUS, 0x16, 0x03 },
+//     /*OK*/  { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+               // 21 & 22? The suggested values look wrong. Go with default
+       /*A*/   { OV511_I2C_BUS, 0x23, 0xc0 },
+       /*A*/   { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
+//     /*OK*/  { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+
+               /* 0x28: 0x05 Selects RGB format if RGB on */
+//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
+//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
+
+       /*OK*/  { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//     /*OK*/  { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
+               { OV511_I2C_BUS, 0x2d, 0x99 },
+//     /*A*/   { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
+//     /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
+//     /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
+//     /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
+//             { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
+//             { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
+//             { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
+               { OV511_I2C_BUS, 0x3d, 0x80 },
+//     /*A*/   { OV511_I2C_BUS, 0x3f, 0x0e },
+
+               /* These next two registers (0x4a, 0x4b) are undocumented. They
+                * control the color balance */
+//     /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
+//     /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
+               { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+       /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
+
+               /* UV average mode, color killer: strongest */
+               { OV511_I2C_BUS, 0x4f, 0x07 },
+
+               { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
+               { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
+               { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
+               { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
+               { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
+//             { OV511_I2C_BUS, 0x5c, 0x10 },
+               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
+       };
+
+       PDEBUG(4, "starting sensor configuration");
+
+       if (init_ov_sensor(ov) < 0) {
+               err("Failed to read sensor ID. You might not have an OV6xx0,");
+               err("or it may be not responding. Report this to " EMAIL);
+               return -1;
+       } else {
+               PDEBUG(1, "OV6xx0 sensor detected");
+       }
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(ov, OV7610_REG_COM_I);
+
+       if (rc < 0) {
+               err("Error detecting sensor type");
+               return -1;
+       }
+
+       if ((rc & 3) == 0) {
+               ov->sensor = SEN_OV6630;
+               info("Sensor is an OV6630");
+       } else if ((rc & 3) == 1) {
+               ov->sensor = SEN_OV6620;
+               info("Sensor is an OV6620");
+       } else if ((rc & 3) == 2) {
+               ov->sensor = SEN_OV6630;
+               info("Sensor is an OV6630AE");
+       } else if ((rc & 3) == 3) {
+               ov->sensor = SEN_OV6630;
+               info("Sensor is an OV6630AF");
+       }
+
+       /* Set sensor-specific vars */
+       ov->maxwidth = 352;
+       ov->maxheight = 288;
+       ov->minwidth = 64;
+       ov->minheight = 48;
+
+       // FIXME: These do not match the actual settings yet
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x80 << 8;
+       ov->colour = 0x80 << 8;
+       ov->hue = 0x80 << 8;
+
+       if (ov->sensor == SEN_OV6620) {
+               PDEBUG(4, "Writing 6x20 registers");
+               if (write_regvals(ov, aRegvalsNorm6x20))
+                       return -1;
+       } else {
+               PDEBUG(4, "Writing 6x30 registers");
+               if (write_regvals(ov, aRegvalsNorm6x30))
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* This initializes the KS0127 and KS0127B video decoders. */
+static int
+ks0127_configure(struct usb_ov511 *ov)
+{
+       int rc;
+
+// FIXME: I don't know how to sync or reset it yet
+#if 0
+       if (ov51x_init_ks_sensor(ov) < 0) {
+               err("Failed to initialize the KS0127");
+               return -1;
+       } else {
+               PDEBUG(1, "KS012x(B) sensor detected");
+       }
+#endif
+
+       /* Detect decoder subtype */
+       rc = i2c_r(ov, 0x00);
+       if (rc < 0) {
+               err("Error detecting sensor type");
+               return -1;
+       } else if (rc & 0x08) {
+               rc = i2c_r(ov, 0x3d);
+               if (rc < 0) {
+                       err("Error detecting sensor type");
+                       return -1;
+               } else if ((rc & 0x0f) == 0) {
+                       info("Sensor is a KS0127");
+                       ov->sensor = SEN_KS0127;
+               } else if ((rc & 0x0f) == 9) {
+                       info("Sensor is a KS0127B Rev. A");
+                       ov->sensor = SEN_KS0127B;
+               }
+       } else {
+               err("Error: Sensor is an unsupported KS0122");
+               return -1;
+       }
+
+       /* Set sensor-specific vars */
+       ov->maxwidth = 640;
+       ov->maxheight = 480;
+       ov->minwidth = 64;
+       ov->minheight = 48;
+
+       // FIXME: These do not match the actual settings yet
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x80 << 8;
+       ov->colour = 0x80 << 8;
+       ov->hue = 0x80 << 8;
+
+       /* This device is not supported yet. Bail out now... */
+       err("This sensor is not supported yet.");
+       return -1;
+
+       return 0;
+}
+
+/* This initializes the SAA7111A video decoder. */
+static int
+saa7111a_configure(struct usb_ov511 *ov)
+{
+       int rc;
+
+       /* Since there is no register reset command, all registers must be
+        * written, otherwise gives erratic results */
+       static struct ov511_regvals aRegvalsNormSAA7111A[] = {
+               { OV511_I2C_BUS, 0x06, 0xce },
+               { OV511_I2C_BUS, 0x07, 0x00 },
+               { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
+               { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
+               { OV511_I2C_BUS, 0x00, 0x00 },
+               { OV511_I2C_BUS, 0x01, 0x00 },
+               { OV511_I2C_BUS, 0x03, 0x23 },
+               { OV511_I2C_BUS, 0x04, 0x00 },
+               { OV511_I2C_BUS, 0x05, 0x00 },
+               { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
+               { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
+               { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
+               { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
+               { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
+               { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
+               { OV511_I2C_BUS, 0x0f, 0x00 },
+               { OV511_I2C_BUS, 0x11, 0x0c },
+               { OV511_I2C_BUS, 0x12, 0x00 },
+               { OV511_I2C_BUS, 0x13, 0x00 },
+               { OV511_I2C_BUS, 0x14, 0x00 },
+               { OV511_I2C_BUS, 0x15, 0x00 },
+               { OV511_I2C_BUS, 0x16, 0x00 },
+               { OV511_I2C_BUS, 0x17, 0x00 },
+               { OV511_I2C_BUS, 0x02, 0xc0 },  /* Composite input 0 */
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+// FIXME: I don't know how to sync or reset it yet
+#if 0
+       if (ov51x_init_saa_sensor(ov) < 0) {
+               err("Failed to initialize the SAA7111A");
+               return -1;
+       } else {
+               PDEBUG(1, "SAA7111A sensor detected");
+       }
+#endif
+
+       /* 640x480 not supported with PAL */
+       if (ov->pal) {
+               ov->maxwidth = 320;
+               ov->maxheight = 240;            /* Even field only */
+       } else {
+               ov->maxwidth = 640;
+               ov->maxheight = 480;            /* Even/Odd fields */
+       }
+
+       ov->minwidth = 320;
+       ov->minheight = 240;            /* Even field only */
+
+       ov->has_decoder = 1;
+       ov->num_inputs = 8;
+       ov->norm = VIDEO_MODE_AUTO;
+       ov->stop_during_set = 0;        /* Decoder guarantees stable image */
+
+       /* Decoder doesn't change these values, so we use these instead of
+        * acutally reading the registers (which doesn't work) */
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x40 << 9;
+       ov->colour = 0x40 << 9;
+       ov->hue = 32768;
+
+       PDEBUG(4, "Writing SAA7111A registers");
+       if (write_regvals(ov, aRegvalsNormSAA7111A))
+               return -1;
+
+       /* Detect version of decoder. This must be done after writing the
+        * initial regs or the decoder will lock up. */
+       rc = i2c_r(ov, 0x00);
+
+       if (rc < 0) {
+               err("Error detecting sensor version");
+               return -1;
+       } else {
+               info("Sensor is an SAA7111A (version 0x%x)", rc);
+               ov->sensor = SEN_SAA7111A;
+       }
+
+       // FIXME: Fix this for OV518(+)
+       /* Latch to negative edge of clock. Otherwise, we get incorrect
+        * colors and jitter in the digital signal. */
+       if (ov->bclass == BCL_OV511)
+               reg_w(ov, 0x11, 0x00);
+       else
+               warn("SAA7111A not yet supported with OV518/OV518+");
+
+       return 0;
+}
+
+/* This initializes the OV511/OV511+ and the sensor */
+static int
+ov511_configure(struct usb_ov511 *ov)
+{
+       static struct ov511_regvals aRegvalsInit511[] = {
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x3f },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x3d },
+               { OV511_DONE_BUS, 0x0, 0x00},
+       };
+
+       static struct ov511_regvals aRegvalsNorm511[] = {
+               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0x01 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R511_FIFO_OPTS,        0x1f },
+               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
+               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       static struct ov511_regvals aRegvalsNorm511Plus[] = {
+               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0xff },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R511_FIFO_OPTS,        0xff },
+               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
+               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       PDEBUG(4, "");
+
+       ov->customid = reg_r(ov, R511_SYS_CUST_ID);
+       if (ov->customid < 0) {
+               err("Unable to read camera bridge registers");
+               goto error;
+       }
+
+       PDEBUG (1, "CustomID = %d", ov->customid);
+       ov->desc = symbolic(camlist, ov->customid);
+       info("model: %s", ov->desc);
+
+       if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
+               err("Camera type (%d) not recognized", ov->customid);
+               err("Please notify " EMAIL " of the name,");
+               err("manufacturer, model, and this number of your camera.");
+               err("Also include the output of the detection process.");
+       }
+
+       if (ov->customid == 70)         /* USB Life TV (PAL/SECAM) */
+               ov->pal = 1;
+
+       if (write_regvals(ov, aRegvalsInit511))
+               goto error;
+
+       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 0);
+
+       /* The OV511+ has undocumented bits in the flow control register.
+        * Setting it to 0xff fixes the corruption with moving objects. */
+       if (ov->bridge == BRG_OV511) {
+               if (write_regvals(ov, aRegvalsNorm511))
+                       goto error;
+       } else if (ov->bridge == BRG_OV511PLUS) {
+               if (write_regvals(ov, aRegvalsNorm511Plus))
+                       goto error;
+       } else {
+               err("Invalid bridge");
+       }
+
+       if (ov511_init_compression(ov))
+               goto error;
+
+       ov->packet_numbering = 1;
+       ov511_set_packet_size(ov, 0);
+
+       ov->snap_enabled = snapshot;
+
+       /* Test for 7xx0 */
+       PDEBUG(3, "Testing for 0V7xx0");
+       ov->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
+               goto error;
+
+       if (i2c_w(ov, 0x12, 0x80) < 0) {
+               /* Test for 6xx0 */
+               PDEBUG(3, "Testing for 0V6xx0");
+               ov->primary_i2c_slave = OV6xx0_SID;
+               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
+                       goto error;
+
+               if (i2c_w(ov, 0x12, 0x80) < 0) {
+                       /* Test for 8xx0 */
+                       PDEBUG(3, "Testing for 0V8xx0");
+                       ov->primary_i2c_slave = OV8xx0_SID;
+                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
+                               goto error;
+
+                       if (i2c_w(ov, 0x12, 0x80) < 0) {
+                               /* Test for SAA7111A */
+                               PDEBUG(3, "Testing for SAA7111A");
+                               ov->primary_i2c_slave = SAA7111A_SID;
+                               if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
+                                       goto error;
+
+                               if (i2c_w(ov, 0x0d, 0x00) < 0) {
+                                       /* Test for KS0127 */
+                                       PDEBUG(3, "Testing for KS0127");
+                                       ov->primary_i2c_slave = KS0127_SID;
+                                       if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
+                                               goto error;
+
+                                       if (i2c_w(ov, 0x10, 0x00) < 0) {
+                                               err("Can't determine sensor slave IDs");
+                                               goto error;
+                                       } else {
+                                               if (ks0127_configure(ov) < 0) {
+                                                       err("Failed to configure KS0127");
+                                                       goto error;
+                                               }
+                                       }
+                               } else {
+                                       if (saa7111a_configure(ov) < 0) {
+                                               err("Failed to configure SAA7111A");
+                                               goto error;
+                                       }
+                               }
+                       } else {
+                               err("Detected unsupported OV8xx0 sensor");
+                               goto error;
+                       }
+               } else {
+                       if (ov6xx0_configure(ov) < 0) {
+                               err("Failed to configure OV6xx0");
+                               goto error;
+                       }
+               }
+       } else {
+               if (ov7xx0_configure(ov) < 0) {
+                       err("Failed to configure OV7xx0");
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       err("OV511 Config failed");
+
+       return -EBUSY;
+}
+
+/* This initializes the OV518/OV518+ and the sensor */
+static int
+ov518_configure(struct usb_ov511 *ov)
+{
+       /* For 518 and 518+ */
+       static struct ov511_regvals aRegvalsInit518[] = {
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x40 },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x3e },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x00 },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
+               { OV511_REG_BUS, 0x46,                  0x00 },
+               { OV511_REG_BUS, 0x5d,                  0x03 },
+               { OV511_DONE_BUS, 0x0, 0x00},
+       };
+
+       static struct ov511_regvals aRegvalsNorm518[] = {
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
+               { OV511_REG_BUS, 0x31,                  0x0f },
+               { OV511_REG_BUS, 0x5d,                  0x03 },
+               { OV511_REG_BUS, 0x24,                  0x9f },
+               { OV511_REG_BUS, 0x25,                  0x90 },
+               { OV511_REG_BUS, 0x20,                  0x00 },
+               { OV511_REG_BUS, 0x51,                  0x04 },
+               { OV511_REG_BUS, 0x71,                  0x19 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       static struct ov511_regvals aRegvalsNorm518Plus[] = {
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
+               { OV511_REG_BUS, 0x31,                  0x0f },
+               { OV511_REG_BUS, 0x5d,                  0x03 },
+               { OV511_REG_BUS, 0x24,                  0x9f },
+               { OV511_REG_BUS, 0x25,                  0x90 },
+               { OV511_REG_BUS, 0x20,                  0x60 },
+               { OV511_REG_BUS, 0x51,                  0x02 },
+               { OV511_REG_BUS, 0x71,                  0x19 },
+               { OV511_REG_BUS, 0x40,                  0xff },
+               { OV511_REG_BUS, 0x41,                  0x42 },
+               { OV511_REG_BUS, 0x46,                  0x00 },
+               { OV511_REG_BUS, 0x33,                  0x04 },
+               { OV511_REG_BUS, 0x21,                  0x19 },
+               { OV511_REG_BUS, 0x3f,                  0x10 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       PDEBUG(4, "");
+
+       /* First 5 bits of custom ID reg are a revision ID on OV518 */
+       info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
+
+       /* Give it the default description */
+       ov->desc = symbolic(camlist, 0);
+
+       if (write_regvals(ov, aRegvalsInit518))
+               goto error;
+
+       /* Set LED GPIO pin to output mode */
+       if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
+               goto error;
+
+       /* LED is off by default with OV518; have to explicitly turn it on */
+       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 0);
+       else
+               ov51x_led_control(ov, 1);
+
+       /* Don't require compression if dumppix is enabled; otherwise it's
+        * required. OV518 has no uncompressed mode, to save RAM. */
+       if (!dumppix && !ov->compress) {
+               ov->compress = 1;
+               warn("Compression required with OV518...enabling");
+       }
+
+       if (ov->bridge == BRG_OV518) {
+               if (write_regvals(ov, aRegvalsNorm518))
+                       goto error;
+       } else if (ov->bridge == BRG_OV518PLUS) {
+               if (write_regvals(ov, aRegvalsNorm518Plus))
+                       goto error;
+       } else {
+               err("Invalid bridge");
+       }
+
+       if (reg_w(ov, 0x2f, 0x80) < 0)
+               goto error;
+
+       if (ov518_init_compression(ov))
+               goto error;
+
+       if (ov->bridge == BRG_OV518)
+       {
+               struct usb_interface *ifp;
+               struct usb_host_interface *alt;
+               __u16 mxps = 0;
+
+               ifp = usb_ifnum_to_if(ov->dev, 0);
+               if (ifp) {
+                       alt = usb_altnum_to_altsetting(ifp, 7);
+                       if (alt)
+                               mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+               }
+
+               /* Some OV518s have packet numbering by default, some don't */
+               if (mxps == 897)
+                       ov->packet_numbering = 1;
+               else
+                       ov->packet_numbering = 0;
+       } else {
+               /* OV518+ has packet numbering turned on by default */
+               ov->packet_numbering = 1;
+       }
+
+       ov518_set_packet_size(ov, 0);
+
+       ov->snap_enabled = snapshot;
+
+       /* Test for 76xx */
+       ov->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
+               goto error;
+
+       /* The OV518 must be more aggressive about sensor detection since
+        * I2C write will never fail if the sensor is not present. We have
+        * to try to initialize the sensor to detect its presence */
+
+       if (init_ov_sensor(ov) < 0) {
+               /* Test for 6xx0 */
+               ov->primary_i2c_slave = OV6xx0_SID;
+               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
+                       goto error;
+
+               if (init_ov_sensor(ov) < 0) {
+                       /* Test for 8xx0 */
+                       ov->primary_i2c_slave = OV8xx0_SID;
+                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
+                               goto error;
+
+                       if (init_ov_sensor(ov) < 0) {
+                               err("Can't determine sensor slave IDs");
+                               goto error;
+                       } else {
+                               err("Detected unsupported OV8xx0 sensor");
+                               goto error;
+                       }
+               } else {
+                       if (ov6xx0_configure(ov) < 0) {
+                               err("Failed to configure OV6xx0");
+                               goto error;
+                       }
+               }
+       } else {
+               if (ov7xx0_configure(ov) < 0) {
+                       err("Failed to configure OV7xx0");
+                       goto error;
+               }
+       }
+
+       ov->maxwidth = 352;
+       ov->maxheight = 288;
+
+       // The OV518 cannot go as low as the sensor can
+       ov->minwidth = 160;
+       ov->minheight = 120;
+
+       return 0;
+
+error:
+       err("OV518 Config failed");
+
+       return -EBUSY;
+}
+
+/****************************************************************************
+ *  sysfs
+ ***************************************************************************/
+
+static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
+{
+       struct video_device *vdev = to_video_device(cd);
+       return video_get_drvdata(vdev);
+}
+
+static ssize_t show_custom_id(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%d\n", ov->customid);
+}
+static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
+
+static ssize_t show_model(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%s\n", ov->desc);
+}
+static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+static ssize_t show_bridge(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
+}
+static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
+
+static ssize_t show_sensor(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
+}
+static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
+
+static ssize_t show_brightness(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_brightness(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+}
+static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+
+static ssize_t show_saturation(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_saturation(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+}
+static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+
+static ssize_t show_contrast(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_contrast(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+}
+static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+
+static ssize_t show_hue(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_hue(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+}
+static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+
+static ssize_t show_exposure(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned char exp = 0;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_exposure(ov, &exp);
+       return sprintf(buf, "%d\n", exp >> 8);
+}
+static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
+
+static void ov_create_sysfs(struct video_device *vdev)
+{
+       video_device_create_file(vdev, &class_device_attr_custom_id);
+       video_device_create_file(vdev, &class_device_attr_model);
+       video_device_create_file(vdev, &class_device_attr_bridge);
+       video_device_create_file(vdev, &class_device_attr_sensor);
+       video_device_create_file(vdev, &class_device_attr_brightness);
+       video_device_create_file(vdev, &class_device_attr_saturation);
+       video_device_create_file(vdev, &class_device_attr_contrast);
+       video_device_create_file(vdev, &class_device_attr_hue);
+       video_device_create_file(vdev, &class_device_attr_exposure);
+}
+
+/****************************************************************************
+ *  USB routines
+ ***************************************************************************/
+
+static int
+ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_interface_descriptor *idesc;
+       struct usb_ov511 *ov;
+       int i;
+
+       PDEBUG(1, "probing for device...");
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       idesc = &intf->cur_altsetting->desc;
+
+       if (idesc->bInterfaceClass != 0xFF)
+               return -ENODEV;
+       if (idesc->bInterfaceSubClass != 0x00)
+               return -ENODEV;
+
+       if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+               err("couldn't kmalloc ov struct");
+               goto error_out;
+       }
+
+       ov->dev = dev;
+       ov->iface = idesc->bInterfaceNumber;
+       ov->led_policy = led;
+       ov->compress = compress;
+       ov->lightfreq = lightfreq;
+       ov->num_inputs = 1;        /* Video decoder init functs. change this */
+       ov->stop_during_set = !fastset;
+       ov->backlight = backlight;
+       ov->mirror = mirror;
+       ov->auto_brt = autobright;
+       ov->auto_gain = autogain;
+       ov->auto_exp = autoexp;
+
+       switch (le16_to_cpu(dev->descriptor.idProduct)) {
+       case PROD_OV511:
+               ov->bridge = BRG_OV511;
+               ov->bclass = BCL_OV511;
+               break;
+       case PROD_OV511PLUS:
+               ov->bridge = BRG_OV511PLUS;
+               ov->bclass = BCL_OV511;
+               break;
+       case PROD_OV518:
+               ov->bridge = BRG_OV518;
+               ov->bclass = BCL_OV518;
+               break;
+       case PROD_OV518PLUS:
+               ov->bridge = BRG_OV518PLUS;
+               ov->bclass = BCL_OV518;
+               break;
+       case PROD_ME2CAM:
+               if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
+                       goto error;
+               ov->bridge = BRG_OV511PLUS;
+               ov->bclass = BCL_OV511;
+               break;
+       default:
+               err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
+               goto error;
+       }
+
+       info("USB %s video device found", symbolic(brglist, ov->bridge));
+
+       init_waitqueue_head(&ov->wq);
+
+       mutex_init(&ov->lock);  /* to 1 == available */
+       mutex_init(&ov->buf_lock);
+       mutex_init(&ov->i2c_lock);
+       mutex_init(&ov->cbuf_lock);
+
+       ov->buf_state = BUF_NOT_ALLOCATED;
+
+       if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
+               err("usb_make_path error");
+               goto error;
+       }
+
+       /* Allocate control transfer buffer. */
+       /* Must be kmalloc()'ed, for DMA compatibility */
+       ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
+       if (!ov->cbuf)
+               goto error;
+
+       if (ov->bclass == BCL_OV518) {
+               if (ov518_configure(ov) < 0)
+                       goto error;
+       } else {
+               if (ov511_configure(ov) < 0)
+                       goto error;
+       }
+
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].framenum = i;
+               init_waitqueue_head(&ov->frame[i].wq);
+       }
+
+       for (i = 0; i < OV511_NUMSBUF; i++) {
+               ov->sbuf[i].ov = ov;
+               spin_lock_init(&ov->sbuf[i].lock);
+               ov->sbuf[i].n = i;
+       }
+
+       /* Unnecessary? (This is done on open(). Need to make sure variables
+        * are properly initialized without this before removing it, though). */
+       if (ov51x_set_default_params(ov) < 0)
+               goto error;
+
+#ifdef OV511_DEBUG
+       if (dump_bridge) {
+               if (ov->bclass == BCL_OV511)
+                       ov511_dump_regs(ov);
+               else
+                       ov518_dump_regs(ov);
+       }
+#endif
+
+       ov->vdev = video_device_alloc();
+       if (!ov->vdev)
+               goto error;
+
+       memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
+       ov->vdev->dev = &dev->dev;
+       video_set_drvdata(ov->vdev, ov);
+
+       for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
+               /* Minor 0 cannot be specified; assume user wants autodetect */
+               if (unit_video[i] == 0)
+                       break;
+
+               if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
+                       unit_video[i]) >= 0) {
+                       break;
+               }
+       }
+
+       /* Use the next available one */
+       if ((ov->vdev->minor == -1) &&
+           video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
+               err("video_register_device failed");
+               goto error;
+       }
+
+       info("Device at %s registered to minor %d", ov->usb_path,
+            ov->vdev->minor);
+
+       usb_set_intfdata(intf, ov);
+       ov_create_sysfs(ov->vdev);
+       return 0;
+
+error:
+       if (ov->vdev) {
+               if (-1 == ov->vdev->minor)
+                       video_device_release(ov->vdev);
+               else
+                       video_unregister_device(ov->vdev);
+               ov->vdev = NULL;
+       }
+
+       if (ov->cbuf) {
+               mutex_lock(&ov->cbuf_lock);
+               kfree(ov->cbuf);
+               ov->cbuf = NULL;
+               mutex_unlock(&ov->cbuf_lock);
+       }
+
+       kfree(ov);
+       ov = NULL;
+
+error_out:
+       err("Camera initialization failed");
+       return -EIO;
+}
+
+static void
+ov51x_disconnect(struct usb_interface *intf)
+{
+       struct usb_ov511 *ov = usb_get_intfdata(intf);
+       int n;
+
+       PDEBUG(3, "");
+
+       usb_set_intfdata (intf, NULL);
+
+       if (!ov)
+               return;
+
+       if (ov->vdev)
+               video_unregister_device(ov->vdev);
+
+       for (n = 0; n < OV511_NUMFRAMES; n++)
+               ov->frame[n].grabstate = FRAME_ERROR;
+
+       ov->curframe = -1;
+
+       /* This will cause the process to request another frame */
+       for (n = 0; n < OV511_NUMFRAMES; n++)
+               wake_up_interruptible(&ov->frame[n].wq);
+
+       wake_up_interruptible(&ov->wq);
+
+       ov->streaming = 0;
+       ov51x_unlink_isoc(ov);
+
+       ov->dev = NULL;
+
+       /* Free the memory */
+       if (ov && !ov->user) {
+               mutex_lock(&ov->cbuf_lock);
+               kfree(ov->cbuf);
+               ov->cbuf = NULL;
+               mutex_unlock(&ov->cbuf_lock);
+
+               ov51x_dealloc(ov);
+               kfree(ov);
+               ov = NULL;
+       }
+
+       PDEBUG(3, "Disconnect complete");
+}
+
+static struct usb_driver ov511_driver = {
+       .name =         "ov511",
+       .id_table =     device_table,
+       .probe =        ov51x_probe,
+       .disconnect =   ov51x_disconnect
+};
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init
+usb_ov511_init(void)
+{
+       int retval;
+
+       retval = usb_register(&ov511_driver);
+       if (retval)
+               goto out;
+
+       info(DRIVER_VERSION " : " DRIVER_DESC);
+
+out:
+       return retval;
+}
+
+static void __exit
+usb_ov511_exit(void)
+{
+       usb_deregister(&ov511_driver);
+       info("driver deregistered");
+
+}
+
+module_init(usb_ov511_init);
+module_exit(usb_ov511_exit);
+
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
new file mode 100644 (file)
index 0000000..12b3d51
--- /dev/null
@@ -0,0 +1,568 @@
+#ifndef __LINUX_OV511_H
+#define __LINUX_OV511_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#define OV511_DEBUG    /* Turn on debug messages */
+
+#ifdef OV511_DEBUG
+       #define PDEBUG(level, fmt, args...) \
+               if (debug >= (level)) info("[%s:%d] " fmt, \
+               __FUNCTION__, __LINE__ , ## args)
+#else
+       #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { \
+       if ((v) < (mi)) (v) = (mi); \
+       else if ((v) > (ma)) (v) = (ma); \
+}
+
+/* --------------------------------- */
+/* DEFINES FOR OV511 AND OTHER CHIPS */
+/* --------------------------------- */
+
+/* USB IDs */
+#define VEND_OMNIVISION        0x05A9
+#define PROD_OV511     0x0511
+#define PROD_OV511PLUS 0xA511
+#define PROD_OV518     0x0518
+#define PROD_OV518PLUS 0xA518
+
+#define VEND_MATTEL    0x0813
+#define PROD_ME2CAM    0x0002
+
+/* --------------------------------- */
+/*     OV51x REGISTER MNEMONICS      */
+/* --------------------------------- */
+
+/* Camera interface register numbers */
+#define R511_CAM_DELAY         0x10
+#define R511_CAM_EDGE          0x11
+#define R511_CAM_PXCNT         0x12
+#define R511_CAM_LNCNT         0x13
+#define R511_CAM_PXDIV         0x14
+#define R511_CAM_LNDIV         0x15
+#define R511_CAM_UV_EN         0x16
+#define R511_CAM_LINE_MODE     0x17
+#define R511_CAM_OPTS          0x18
+
+/* Snapshot mode camera interface register numbers */
+#define R511_SNAP_FRAME                0x19
+#define R511_SNAP_PXCNT                0x1A
+#define R511_SNAP_LNCNT                0x1B
+#define R511_SNAP_PXDIV                0x1C
+#define R511_SNAP_LNDIV                0x1D
+#define R511_SNAP_UV_EN                0x1E
+#define R511_SNAP_OPTS         0x1F
+
+/* DRAM register numbers */
+#define R511_DRAM_FLOW_CTL     0x20
+#define R511_DRAM_ARCP         0x21
+#define R511_DRAM_MRC          0x22
+#define R511_DRAM_RFC          0x23
+
+/* ISO FIFO register numbers */
+#define R51x_FIFO_PSIZE                0x30    /* 2 bytes wide w/ OV518(+) */
+#define R511_FIFO_OPTS         0x31
+
+/* Parallel IO register numbers */
+#define R511_PIO_OPTS          0x38
+#define R511_PIO_DATA          0x39
+#define R511_PIO_BIST          0x3E
+#define R518_GPIO_IN           0x55    /* OV518(+) only */
+#define R518_GPIO_OUT          0x56    /* OV518(+) only */
+#define R518_GPIO_CTL          0x57    /* OV518(+) only */
+#define R518_GPIO_PULSE_IN     0x58    /* OV518(+) only */
+#define R518_GPIO_PULSE_CLEAR  0x59    /* OV518(+) only */
+#define R518_GPIO_PULSE_POL    0x5a    /* OV518(+) only */
+#define R518_GPIO_PULSE_EN     0x5b    /* OV518(+) only */
+#define R518_GPIO_RESET                0x5c    /* OV518(+) only */
+
+/* I2C registers */
+#define R511_I2C_CTL           0x40
+#define R518_I2C_CTL           0x47    /* OV518(+) only */
+#define R51x_I2C_W_SID         0x41
+#define R51x_I2C_SADDR_3       0x42
+#define R51x_I2C_SADDR_2       0x43
+#define R51x_I2C_R_SID         0x44
+#define R51x_I2C_DATA          0x45
+#define R51x_I2C_CLOCK         0x46
+#define R51x_I2C_TIMEOUT       0x47
+
+/* I2C snapshot registers */
+#define R511_SI2C_SADDR_3      0x48
+#define R511_SI2C_DATA         0x49
+
+/* System control registers */
+#define R51x_SYS_RESET         0x50
+               /* Reset type definitions */
+#define        OV511_RESET_UDC         0x01
+#define        OV511_RESET_I2C         0x02
+#define        OV511_RESET_FIFO        0x04
+#define        OV511_RESET_OMNICE      0x08
+#define        OV511_RESET_DRAM        0x10
+#define        OV511_RESET_CAM_INT     0x20
+#define        OV511_RESET_OV511       0x40
+#define        OV511_RESET_NOREGS      0x3F /* All but OV511 & regs */
+#define        OV511_RESET_ALL         0x7F
+
+#define R511_SYS_CLOCK_DIV     0x51
+#define R51x_SYS_SNAP          0x52
+#define R51x_SYS_INIT          0x53
+#define R511_SYS_PWR_CLK       0x54 /* OV511+/OV518(+) only */
+#define R511_SYS_LED_CTL       0x55 /* OV511+ only */
+#define R511_SYS_USER          0x5E
+#define R511_SYS_CUST_ID       0x5F
+
+/* OmniCE (compression) registers */
+#define R511_COMP_PHY          0x70
+#define R511_COMP_PHUV         0x71
+#define R511_COMP_PVY          0x72
+#define R511_COMP_PVUV         0x73
+#define R511_COMP_QHY          0x74
+#define R511_COMP_QHUV         0x75
+#define R511_COMP_QVY          0x76
+#define R511_COMP_QVUV         0x77
+#define R511_COMP_EN           0x78
+#define R511_COMP_LUT_EN       0x79
+#define R511_COMP_LUT_BEGIN    0x80
+
+/* --------------------------------- */
+/*         ALTERNATE NUMBERS         */
+/* --------------------------------- */
+
+/* Alternate numbers for various max packet sizes (OV511 only) */
+#define OV511_ALT_SIZE_992     0
+#define OV511_ALT_SIZE_993     1
+#define OV511_ALT_SIZE_768     2
+#define OV511_ALT_SIZE_769     3
+#define OV511_ALT_SIZE_512     4
+#define OV511_ALT_SIZE_513     5
+#define OV511_ALT_SIZE_257     6
+#define OV511_ALT_SIZE_0       7
+
+/* Alternate numbers for various max packet sizes (OV511+ only) */
+#define OV511PLUS_ALT_SIZE_0   0
+#define OV511PLUS_ALT_SIZE_33  1
+#define OV511PLUS_ALT_SIZE_129 2
+#define OV511PLUS_ALT_SIZE_257 3
+#define OV511PLUS_ALT_SIZE_385 4
+#define OV511PLUS_ALT_SIZE_513 5
+#define OV511PLUS_ALT_SIZE_769 6
+#define OV511PLUS_ALT_SIZE_961 7
+
+/* Alternate numbers for various max packet sizes (OV518(+) only) */
+#define OV518_ALT_SIZE_0       0
+#define OV518_ALT_SIZE_128     1
+#define OV518_ALT_SIZE_256     2
+#define OV518_ALT_SIZE_384     3
+#define OV518_ALT_SIZE_512     4
+#define OV518_ALT_SIZE_640     5
+#define OV518_ALT_SIZE_768     6
+#define OV518_ALT_SIZE_896     7
+
+/* --------------------------------- */
+/*     OV7610 REGISTER MNEMONICS     */
+/* --------------------------------- */
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN          0x00  /* gain setting (5:0) */
+#define OV7610_REG_BLUE          0x01  /* blue channel balance */
+#define OV7610_REG_RED           0x02  /* red channel balance */
+#define OV7610_REG_SAT           0x03  /* saturation */
+                                       /* 04 reserved */
+#define OV7610_REG_CNT           0x05  /* Y contrast */
+#define OV7610_REG_BRT           0x06  /* Y brightness */
+                                       /* 08-0b reserved */
+#define OV7610_REG_BLUE_BIAS     0x0C  /* blue channel bias (5:0) */
+#define OV7610_REG_RED_BIAS      0x0D  /* read channel bias (5:0) */
+#define OV7610_REG_GAMMA_COEFF   0x0E  /* gamma settings */
+#define OV7610_REG_WB_RANGE      0x0F  /* AEC/ALC/S-AWB settings */
+#define OV7610_REG_EXP           0x10  /* manual exposure setting */
+#define OV7610_REG_CLOCK         0x11  /* polarity/clock prescaler */
+#define OV7610_REG_COM_A         0x12  /* misc common regs */
+#define OV7610_REG_COM_B         0x13  /* misc common regs */
+#define OV7610_REG_COM_C         0x14  /* misc common regs */
+#define OV7610_REG_COM_D         0x15  /* misc common regs */
+#define OV7610_REG_FIELD_DIVIDE  0x16  /* field interval/mode settings */
+#define OV7610_REG_HWIN_START    0x17  /* horizontal window start */
+#define OV7610_REG_HWIN_END      0x18  /* horizontal window end */
+#define OV7610_REG_VWIN_START    0x19  /* vertical window start */
+#define OV7610_REG_VWIN_END      0x1A  /* vertical window end */
+#define OV7610_REG_PIXEL_SHIFT   0x1B  /* pixel shift */
+#define OV7610_REG_ID_HIGH       0x1C  /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW        0x1D  /* manufacturer ID LSB */
+                                       /* 0e-0f reserved */
+#define OV7610_REG_COM_E         0x20  /* misc common regs */
+#define OV7610_REG_YOFFSET       0x21  /* Y channel offset */
+#define OV7610_REG_UOFFSET       0x22  /* U channel offset */
+                                       /* 23 reserved */
+#define OV7610_REG_ECW           0x24  /* Exposure white level for AEC */
+#define OV7610_REG_ECB           0x25  /* Exposure black level for AEC */
+#define OV7610_REG_COM_F         0x26  /* misc settings */
+#define OV7610_REG_COM_G         0x27  /* misc settings */
+#define OV7610_REG_COM_H         0x28  /* misc settings */
+#define OV7610_REG_COM_I         0x29  /* misc settings */
+#define OV7610_REG_FRAMERATE_H   0x2A  /* frame rate MSB + misc */
+#define OV7610_REG_FRAMERATE_L   0x2B  /* frame rate LSB */
+#define OV7610_REG_ALC           0x2C  /* Auto Level Control settings */
+#define OV7610_REG_COM_J         0x2D  /* misc settings */
+#define OV7610_REG_VOFFSET       0x2E  /* V channel offset adjustment */
+#define OV7610_REG_ARRAY_BIAS   0x2F   /* Array bias -- don't change */
+                                       /* 30-32 reserved */
+#define OV7610_REG_YGAMMA        0x33  /* misc gamma settings (7:6) */
+#define OV7610_REG_BIAS_ADJUST   0x34  /* misc bias settings */
+#define OV7610_REG_COM_L         0x35  /* misc settings */
+                                       /* 36-37 reserved */
+#define OV7610_REG_COM_K         0x38  /* misc registers */
+
+/* --------------------------------- */
+/*           I2C ADDRESSES           */
+/* --------------------------------- */
+
+#define OV7xx0_SID   0x42
+#define OV6xx0_SID   0xC0
+#define OV8xx0_SID   0xA0
+#define KS0127_SID   0xD8
+#define SAA7111A_SID 0x48
+
+/* --------------------------------- */
+/*       MISCELLANEOUS DEFINES       */
+/* --------------------------------- */
+
+#define I2C_CLOCK_PRESCALER    0x03
+
+#define FRAMES_PER_DESC                10      /* FIXME - What should this be? */
+#define MAX_FRAME_SIZE_PER_DESC        993     /* For statically allocated stuff */
+#define PIXELS_PER_SEG         256     /* Pixels per segment */
+
+#define OV511_ENDPOINT_ADDRESS 1       /* Isoc endpoint number */
+
+#define OV511_NUMFRAMES        2
+#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
+       #error "OV511_NUMFRAMES is too high"
+#endif
+
+#define OV511_NUMSBUF          2
+
+/* Control transfers use up to 4 bytes */
+#define OV511_CBUF_SIZE                4
+
+/* Size of usb_make_path() buffer */
+#define OV511_USB_PATH_LEN     64
+
+/* Bridge types */
+enum {
+       BRG_UNKNOWN,
+       BRG_OV511,
+       BRG_OV511PLUS,
+       BRG_OV518,
+       BRG_OV518PLUS,
+};
+
+/* Bridge classes */
+enum {
+       BCL_UNKNOWN,
+       BCL_OV511,
+       BCL_OV518,
+};
+
+/* Sensor types */
+enum {
+       SEN_UNKNOWN,
+       SEN_OV76BE,
+       SEN_OV7610,
+       SEN_OV7620,
+       SEN_OV7620AE,
+       SEN_OV6620,
+       SEN_OV6630,
+       SEN_OV6630AE,
+       SEN_OV6630AF,
+       SEN_OV8600,
+       SEN_KS0127,
+       SEN_KS0127B,
+       SEN_SAA7111A,
+};
+
+enum {
+       STATE_SCANNING,         /* Scanning for start */
+       STATE_HEADER,           /* Parsing header */
+       STATE_LINES,            /* Parsing lines */
+};
+
+/* Buffer states */
+enum {
+       BUF_NOT_ALLOCATED,
+       BUF_ALLOCATED,
+};
+
+/* --------- Definition of ioctl interface --------- */
+
+#define OV511_INTERFACE_VER 101
+
+/* LED options */
+enum {
+       LED_OFF,
+       LED_ON,
+       LED_AUTO,
+};
+
+/* Raw frame formats */
+enum {
+       RAWFMT_INVALID,
+       RAWFMT_YUV400,
+       RAWFMT_YUV420,
+       RAWFMT_YUV422,
+       RAWFMT_GBR422,
+};
+
+struct ov511_i2c_struct {
+       unsigned char slave; /* Write slave ID (read ID - 1) */
+       unsigned char reg;   /* Index of register */
+       unsigned char value; /* User sets this w/ write, driver does w/ read */
+       unsigned char mask;  /* Bits to be changed. Not used with read ops */
+};
+
+/* ioctls */
+#define OV511IOC_WI2C     _IOW('v', BASE_VIDIOCPRIVATE + 5, \
+                              struct ov511_i2c_struct)
+#define OV511IOC_RI2C    _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
+                              struct ov511_i2c_struct)
+/* ------------- End IOCTL interface -------------- */
+
+struct usb_ov511;              /* Forward declaration */
+
+struct ov511_sbuf {
+       struct usb_ov511 *ov;
+       unsigned char *data;
+       struct urb *urb;
+       spinlock_t lock;
+       int n;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+struct ov511_regvals {
+       enum {
+               OV511_DONE_BUS,
+               OV511_REG_BUS,
+               OV511_I2C_BUS,
+       } bus;
+       unsigned char reg;
+       unsigned char val;
+};
+
+struct ov511_frame {
+       int framenum;           /* Index of this frame */
+       unsigned char *data;    /* Frame buffer */
+       unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
+       unsigned char *rawdata; /* Raw camera data buffer */
+       unsigned char *compbuf; /* Temp buffer for decompressor */
+
+       int depth;              /* Bytes per pixel */
+       int width;              /* Width application is expecting */
+       int height;             /* Height application is expecting */
+
+       int rawwidth;           /* Actual width of frame sent from camera */
+       int rawheight;          /* Actual height of frame sent from camera */
+
+       int sub_flag;           /* Sub-capture mode for this frame? */
+       unsigned int format;    /* Format for this frame */
+       int compressed;         /* Is frame compressed? */
+
+       volatile int grabstate; /* State of grabbing */
+       int scanstate;          /* State of scanning */
+
+       int bytes_recvd;        /* Number of image bytes received from camera */
+
+       long bytes_read;        /* Amount that has been read() */
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int snapshot;           /* True if frame was a snapshot */
+};
+
+#define DECOMP_INTERFACE_VER 4
+
+/* Compression module operations */
+struct ov51x_decomp_ops {
+       int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
+                         int, int, int);
+       int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
+                         int, int, int);
+       int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
+                         int, int, int);
+       struct module *owner;
+};
+
+struct usb_ov511 {
+       struct video_device *vdev;
+       struct usb_device *dev;
+
+       int customid;
+       char *desc;
+       unsigned char iface;
+       char usb_path[OV511_USB_PATH_LEN];
+
+       /* Determined by sensor type */
+       int maxwidth;
+       int maxheight;
+       int minwidth;
+       int minheight;
+
+       int brightness;
+       int colour;
+       int contrast;
+       int hue;
+       int whiteness;
+       int exposure;
+       int auto_brt;           /* Auto brightness enabled flag */
+       int auto_gain;          /* Auto gain control enabled flag */
+       int auto_exp;           /* Auto exposure enabled flag */
+       int backlight;          /* Backlight exposure algorithm flag */
+       int mirror;             /* Image is reversed horizontally */
+
+       int led_policy;         /* LED: off|on|auto; OV511+ only */
+
+       struct mutex lock;      /* Serializes user-accessible operations */
+       int user;               /* user count for exclusive use */
+
+       int streaming;          /* Are we streaming Isochronous? */
+       int grabbing;           /* Are we grabbing? */
+
+       int compress;           /* Should the next frame be compressed? */
+       int compress_inited;    /* Are compression params uploaded? */
+
+       int lightfreq;          /* Power (lighting) frequency */
+       int bandfilt;           /* Banding filter enabled flag */
+
+       unsigned char *fbuf;    /* Videodev buffer area */
+       unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
+       unsigned char *rawfbuf; /* Raw camera data buffer area */
+
+       int sub_flag;           /* Pix Array subcapture on flag */
+       int subx;               /* Pix Array subcapture x offset */
+       int suby;               /* Pix Array subcapture y offset */
+       int subw;               /* Pix Array subcapture width */
+       int subh;               /* Pix Array subcapture height */
+
+       int curframe;           /* Current receiving sbuf */
+       struct ov511_frame frame[OV511_NUMFRAMES];
+
+       struct ov511_sbuf sbuf[OV511_NUMSBUF];
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int snap_enabled;       /* Snapshot mode enabled */
+
+       int bridge;             /* Type of bridge (BRG_*) */
+       int bclass;             /* Class of bridge (BCL_*) */
+       int sensor;             /* Type of image sensor chip (SEN_*) */
+
+       int packet_size;        /* Frame size per isoc desc */
+       int packet_numbering;   /* Is ISO frame numbering enabled? */
+
+       /* Framebuffer/sbuf management */
+       int buf_state;
+       struct mutex buf_lock;
+
+       struct ov51x_decomp_ops *decomp_ops;
+
+       /* Stop streaming while changing picture settings */
+       int stop_during_set;
+
+       int stopped;            /* Streaming is temporarily paused */
+
+       /* Video decoder stuff */
+       int input;              /* Composite, S-VIDEO, etc... */
+       int num_inputs;         /* Number of inputs */
+       int norm;               /* NTSC / PAL / SECAM */
+       int has_decoder;        /* Device has a video decoder */
+       int pal;                /* Device is designed for PAL resolution */
+
+       /* I2C interface */
+       struct mutex i2c_lock;    /* Protect I2C controller regs */
+       unsigned char primary_i2c_slave;  /* I2C write id of sensor */
+
+       /* Control transaction stuff */
+       unsigned char *cbuf;            /* Buffer for payload */
+       struct mutex cbuf_lock;
+};
+
+/* Used to represent a list of values and their respective symbolic names */
+struct symbolic_list {
+       int num;
+       char *name;
+};
+
+#define NOT_DEFINED_STR "Unknown"
+
+/* Returns the name of the matching element in the symbolic_list array. The
+ * end of the list must be marked with an element that has a NULL name.
+ */
+static inline char *
+symbolic(struct symbolic_list list[], int num)
+{
+       int i;
+
+       for (i = 0; list[i].name != NULL; i++)
+                       if (list[i].num == num)
+                               return (list[i].name);
+
+       return (NOT_DEFINED_STR);
+}
+
+/* Compression stuff */
+
+#define OV511_QUANTABLESIZE    64
+#define OV518_QUANTABLESIZE    32
+
+#define OV511_YQUANTABLE { \
+       0, 1, 1, 2, 2, 3, 3, 4, \
+       1, 1, 1, 2, 2, 3, 4, 4, \
+       1, 1, 2, 2, 3, 4, 4, 4, \
+       2, 2, 2, 3, 4, 4, 4, 4, \
+       2, 2, 3, 4, 4, 5, 5, 5, \
+       3, 3, 4, 4, 5, 5, 5, 5, \
+       3, 4, 4, 4, 5, 5, 5, 5, \
+       4, 4, 4, 4, 5, 5, 5, 5  \
+}
+
+#define OV511_UVQUANTABLE { \
+       0, 2, 2, 3, 4, 4, 4, 4, \
+       2, 2, 2, 4, 4, 4, 4, 4, \
+       2, 2, 3, 4, 4, 4, 4, 4, \
+       3, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4  \
+}
+
+#define OV518_YQUANTABLE { \
+       5, 4, 5, 6, 6, 7, 7, 7, \
+       5, 5, 5, 5, 6, 7, 7, 7, \
+       6, 6, 6, 6, 7, 7, 7, 8, \
+       7, 7, 6, 7, 7, 7, 8, 8  \
+}
+
+#define OV518_UVQUANTABLE { \
+       6, 6, 6, 7, 7, 7, 7, 7, \
+       6, 6, 6, 7, 7, 7, 7, 7, \
+       6, 6, 6, 7, 7, 7, 7, 8, \
+       7, 7, 7, 7, 7, 7, 8, 8  \
+}
+
+#endif
index bca41ad93de85bb189b4dc0a2a148092fdca68c7..cba4cdf20f4980a240110ea23db667983e30dedd 100644 (file)
@@ -1,4 +1,4 @@
 ovcamchip-objs     := ovcamchip_core.o ov6x20.o ov6x30.o ov7x10.o ov7x20.o \
-                      ov76be.o
+                     ov76be.o
 
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip.o
index e76b53d5909cf97cbca24634f2df1e5adc4cfb74..3fe9fa04cd8419332d8e1ee1bf601e166a78b10a 100644 (file)
@@ -266,17 +266,17 @@ static int ovcamchip_detect(struct i2c_client *c)
                PDEBUG(3, "Testing for 0V6xx0");
                c->addr = OV6xx0_SID;
                if (init_camchip(c) < 0) {
-                       return -ENODEV;
+                       return -ENODEV;
                } else {
                        if (ov6xx0_detect(c) < 0) {
                                PERROR("Failed to init OV6xx0");
-                               return -EIO;
+                               return -EIO;
                        }
                }
        } else {
                if (ov7xx0_detect(c) < 0) {
                        PERROR("Failed to init OV7xx0");
-                       return -EIO;
+                       return -EIO;
                }
        }
 
index 575e612a554655c1036f59d9e62b244c41dd7ddf..1231335a9f4ac345a0d312bc7da0787daec73d0c 100644 (file)
@@ -82,6 +82,6 @@ extern int ov_write_regvals(struct i2c_client *c,
                            struct ovcamchip_regvals *rvals);
 
 extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
-                        unsigned char value, unsigned char mask);
+                        unsigned char value, unsigned char mask);
 
 #endif
index 15fd85acabda445e3c2046ba56037e30baa0d182..522e9ddeb08903db631aa237c46ded58716eb14c 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     planb - PlanB frame grabber driver
 
     PlanB is used in the 7x00/8x00 series of PowerMacintosh
@@ -584,7 +584,7 @@ finish:
        wake_up_interruptible(&pb->suspendq);
 }
 
-static void add_clip(struct planb *pb, struct video_clip *clip) 
+static void add_clip(struct planb *pb, struct video_clip *clip)
 {
        volatile unsigned char  *base;
        int     xc = clip->x, yc = clip->y;
@@ -758,7 +758,7 @@ static void cmd_buff(struct planb *pb)
                                                        PLANB_SET(CH_SYNC));
        tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
                                                        PLANB_SET(DMA_ABORT));
-       
+
        /* odd field data: */
        jump = virt_to_bus(c1 + nlines / 2);
        for (i=1; i < nlines; i += stepsize, c1++)
@@ -1247,7 +1247,7 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
        tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
        tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
                PLANB_SET(DMA_ABORT));
-       
+
        /* odd field data: */
        jump_addr = c1 + TAB_FACTOR * nlines / 2;
        jump = virt_to_bus(jump_addr);
@@ -1383,7 +1383,7 @@ static int planb_open(struct video_device *dev, int mode)
        pb->user++;
 
        DEBUG("PlanB: device opened\n");
-       return 0;   
+       return 0;
 }
 
 static void planb_close(struct video_device *dev)
@@ -1424,9 +1424,9 @@ static long planb_write(struct video_device *v, const char *buf,
 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
        struct planb *pb=(struct planb *)dev;
-       
+
        switch (cmd)
-       {       
+       {
                case VIDIOCGCAP:
                {
                        struct video_capability b;
@@ -1440,26 +1440,26 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        b.channels = 2; /* composite & svhs */
                        b.audios = 0;
                        b.maxwidth = PLANB_MAXPIXELS;
-                        b.maxheight = PLANB_MAXLINES;
-                        b.minwidth = 32; /* wild guess */
-                        b.minheight = 32;
-                        if (copy_to_user(arg,&b,sizeof(b)))
-                                return -EFAULT;
+                       b.maxheight = PLANB_MAXLINES;
+                       b.minwidth = 32; /* wild guess */
+                       b.minheight = 32;
+                       if (copy_to_user(arg,&b,sizeof(b)))
+                               return -EFAULT;
                        return 0;
                }
                case VIDIOCSFBUF:
                {
-                        struct video_buffer v;
+                       struct video_buffer v;
                        unsigned short bpp;
                        unsigned int fmt;
 
                        DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
 
-                        if (!capable(CAP_SYS_ADMIN)
+                       if (!capable(CAP_SYS_ADMIN)
                        || !capable(CAP_SYS_RAWIO))
-                                return -EPERM;
-                        if (copy_from_user(&v, arg,sizeof(v)))
-                                return -EFAULT;
+                               return -EPERM;
+                       if (copy_from_user(&v, arg,sizeof(v)))
+                               return -EFAULT;
                        planb_lock(pb);
                        switch(v.depth) {
                        case 8:
@@ -1478,7 +1478,7 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                break;
                        default:
                                planb_unlock(pb);
-                                return -EINVAL;
+                               return -EINVAL;
                        }
                        if (bpp * v.width > v.bytesperline) {
                                planb_unlock(pb);
@@ -1493,7 +1493,7 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        pb->win.bpl = pb->win.bpp * pb->win.swidth;
                        pb->win.pad = v.bytesperline - pb->win.bpl;
 
-                        DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
+                       DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
                                " bpl %d (+ %d)\n", v.base, v.width,v.height,
                                pb->win.bpp, pb->win.bpl, pb->win.pad);
 
@@ -1504,11 +1504,11 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                resume_overlay(pb);
                        }
                        planb_unlock(pb);
-                       return 0;               
+                       return 0;
                }
                case VIDIOCGFBUF:
                {
-                        struct video_buffer v;
+                       struct video_buffer v;
 
                        DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
 
@@ -1518,15 +1518,15 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.depth = pb->win.depth;
                        v.bytesperline = pb->win.bpl + pb->win.pad;
                        if (copy_to_user(arg, &v, sizeof(v)))
-                                return -EFAULT;
+                               return -EFAULT;
                        return 0;
                }
                case VIDIOCCAPTURE:
                {
                        int i;
 
-                        if(copy_from_user(&i, arg, sizeof(i)))
-                                return -EFAULT;
+                       if(copy_from_user(&i, arg, sizeof(i)))
+                               return -EFAULT;
                        if(i==0) {
                                DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
 
@@ -1695,7 +1695,7 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        struct video_window     vw;
                        struct video_clip       clip;
                        int                     i;
-                       
+
                        DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
 
                        if(copy_from_user(&vw,arg,sizeof(vw)))
@@ -1749,7 +1749,7 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                return -EFAULT;
                        return 0;
                }
-               case VIDIOCSYNC: {
+               case VIDIOCSYNC: {
                        int i;
 
                        IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
@@ -1759,42 +1759,42 @@ static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 
                        IDEBUG("PlanB: sync to frame %d\n", i);
 
-                        if(i > (MAX_GBUFFERS - 1) || i < 0)
-                                return -EINVAL;
+                       if(i > (MAX_GBUFFERS - 1) || i < 0)
+                               return -EINVAL;
 chk_grab:
-                        switch (pb->frame_stat[i]) {
-                        case GBUFFER_UNUSED:
-                                return -EINVAL;
+                       switch (pb->frame_stat[i]) {
+                       case GBUFFER_UNUSED:
+                               return -EINVAL;
                        case GBUFFER_GRABBING:
                                IDEBUG("PlanB: waiting for grab"
                                                        " done (%d)\n", i);
-                               interruptible_sleep_on(&pb->capq);
+                               interruptible_sleep_on(&pb->capq);
                                if(signal_pending(current))
                                        return -EINTR;
                                goto chk_grab;
-                        case GBUFFER_DONE:
-                                pb->frame_stat[i] = GBUFFER_UNUSED;
-                                break;
-                        }
-                        return 0;
+                       case GBUFFER_DONE:
+                               pb->frame_stat[i] = GBUFFER_UNUSED;
+                               break;
+                       }
+                       return 0;
                }
 
-               case VIDIOCMCAPTURE:
+               case VIDIOCMCAPTURE:
                {
-                        struct video_mmap vm;
+                       struct video_mmap vm;
                        volatile unsigned int status;
 
                        IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
 
                        if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
                                return -EFAULT;
-                        status = pb->frame_stat[vm.frame];
-                        if (status != GBUFFER_UNUSED)
-                                return -EBUSY;
+                       status = pb->frame_stat[vm.frame];
+                       if (status != GBUFFER_UNUSED)
+                               return -EBUSY;
 
-                       return vgrab(pb, &vm);
+                       return vgrab(pb, &vm);
                }
-               
+
                case VIDIOCGMBUF:
                {
                        int i;
@@ -1811,7 +1811,7 @@ chk_grab:
                                return -EFAULT;
                        return 0;
                }
-               
+
                case PLANBIOCGSAAREGS:
                {
                        struct planb_saa_regs preg;
@@ -1828,7 +1828,7 @@ chk_grab:
                                return -EFAULT;
                        return 0;
                }
-               
+
                case PLANBIOCSSAAREGS:
                {
                        struct planb_saa_regs preg;
@@ -1842,7 +1842,7 @@ chk_grab:
                        saa_set (preg.addr, preg.val, pb);
                        return 0;
                }
-               
+
                case PLANBIOCGSTAT:
                {
                        struct planb_stat_regs pstat;
@@ -1859,7 +1859,7 @@ chk_grab:
                                return -EFAULT;
                        return 0;
                }
-               
+
                case PLANBIOCSMODE: {
                        int v;
 
@@ -1985,10 +1985,10 @@ static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, cons
 {
        int i;
        struct planb *pb = (struct planb *)dev;
-        unsigned long start = (unsigned long)adr;
+       unsigned long start = (unsigned long)adr;
 
        if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
-               return -EINVAL;
+               return -EINVAL;
        if (!pb->rawbuf) {
                int err;
                if((err=grabbuf_alloc(pb)))
@@ -2091,10 +2091,10 @@ static int init_planb(struct planb *pb)
        /* clear interrupt mask */
        pb->intr_mask = PLANB_CLR_IRQ;
 
-        result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
-        if (result < 0) {
-               if (result==-EINVAL)
-                       printk(KERN_ERR "PlanB: Bad irq number (%d) "
+       result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
+       if (result < 0) {
+               if (result==-EINVAL)
+                       printk(KERN_ERR "PlanB: Bad irq number (%d) "
                                                "or handler\n", (int)pb->irq);
                else if (result==-EBUSY)
                        printk(KERN_ERR "PlanB: I don't know why, "
@@ -2102,7 +2102,7 @@ static int init_planb(struct planb *pb)
                return result;
        }
        disable_irq(pb->irq);
-        
+
        /* Now add the template and register the device unit. */
        memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
 
@@ -2143,7 +2143,7 @@ static int init_planb(struct planb *pb)
 }
 
 /*
- *     Scan for a PlanB controller, request the irq and map the io memory 
+ *     Scan for a PlanB controller, request the irq and map the io memory
  */
 
 static int find_planb(void)
@@ -2171,9 +2171,9 @@ static int find_planb(void)
        pb = &planbs[0];
        planb_num = 1;
 
-        if (planb_devices->n_addrs != 1) {
-                printk (KERN_WARNING "PlanB: expecting 1 address for planb "
-                       "(got %d)", planb_devices->n_addrs);
+       if (planb_devices->n_addrs != 1) {
+               printk (KERN_WARNING "PlanB: expecting 1 address for planb "
+                       "(got %d)", planb_devices->n_addrs);
                return 0;
        }
 
@@ -2236,7 +2236,7 @@ static int find_planb(void)
        pb->planb_base = planb_regs;
        pb->planb_base_phys = (struct planb_registers *)new_base;
        pb->irq = irq;
-       
+
        return planb_num;
 
 err_out_disable:
@@ -2251,7 +2251,7 @@ static void release_planb(void)
        int i;
        struct planb *pb;
 
-       for (i=0;i<planb_num; i++) 
+       for (i=0;i<planb_num; i++)
        {
                pb=&planbs[i];
 
@@ -2278,7 +2278,7 @@ static void release_planb(void)
 static int __init init_planbs(void)
 {
        int i;
-  
+
        if (find_planb()<=0)
                return -EIO;
 
@@ -2288,9 +2288,9 @@ static int __init init_planbs(void)
                                                        " with v4l\n", i);
                        release_planb();
                        return -EIO;
-               } 
+               }
                printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
-       }  
+       }
        return 0;
 }
 
index 79b6b561426eb68ba24dd5268e915e504c1c566d..92823211d0c5957989e02552de636f6cc5072886 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     planb - PlanB frame grabber driver
 
     PlanB is used in the 7x00/8x00 series of PowerMacintosh
@@ -167,7 +167,7 @@ struct planb {
        struct  video_device video_dev;
        struct  video_picture picture;          /* Current picture params */
        struct  video_audio audio_dev;          /* Current audio params */
-  
+
        volatile struct planb_registers *planb_base;    /* virt base of planb */
        struct planb_registers *planb_base_phys;        /* phys base of planb */
        void    *priv_space;                    /* Org. alloc. mem for kfree */
@@ -209,7 +209,7 @@ struct planb {
        int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS];
        unsigned int gfmt[MAX_GBUFFERS];
        int gnorm_switch[MAX_GBUFFERS];
-        volatile unsigned int *frame_stat;
+       volatile unsigned int *frame_stat;
 #define GBUFFER_UNUSED       0x00U
 #define GBUFFER_GRABBING     0x01U
 #define GBUFFER_DONE         0x02U
index 05ca55939e771a30f8c02320f23937c0449aaefa..09835ca098b169b4226c1da8f030786776559e35 100644 (file)
  *     Most of this code is directly derived from his userspace driver.
  *     His driver works so send any reports to alan@redhat.com unless the
  *     userspace driver also doesn't work for you...
- *      
+ *
  *      Changes:
  *      08/07/2003        Daniele Bellucci <bellucda@tiscali.it>
- *                        - pms_capture: report back -EFAULT 
+ *                        - pms_capture: report back -EFAULT
  */
 
 #include <linux/module.h>
@@ -66,14 +66,14 @@ static int standard                 = 0;    /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
 /*
  *     I/O ports and Shared Memory
  */
+
 static int io_port             =       0x250;
 static int data_port           =       0x251;
 static int mem_base            =       0xC8000;
 static void __iomem *mem;
 static int video_nr             =       -1;
 
-       
+
 
 static inline void mvv_write(u8 index, u8 value)
 {
@@ -90,9 +90,9 @@ static int pms_i2c_stat(u8 slave)
 {
        int counter;
        int i;
-       
+
        outb(0x28, io_port);
-       
+
        counter=0;
        while((inb(data_port)&0x01)==0)
                if(counter++==256)
@@ -101,9 +101,9 @@ static int pms_i2c_stat(u8 slave)
        while((inb(data_port)&0x01)!=0)
                if(counter++==256)
                        break;
-                       
+
        outb(slave, io_port);
-       
+
        counter=0;
        while((inb(data_port)&0x01)==0)
                if(counter++==256)
@@ -112,7 +112,7 @@ static int pms_i2c_stat(u8 slave)
        while((inb(data_port)&0x01)!=0)
                if(counter++==256)
                        break;
-                       
+
        for(i=0;i<12;i++)
        {
                char st=inb(data_port);
@@ -122,7 +122,7 @@ static int pms_i2c_stat(u8 slave)
                        break;
        }
        outb(0x29, io_port);
-       return inb(data_port);          
+       return inb(data_port);
 }
 
 static int pms_i2c_write(u16 slave, u16 sub, u16 data)
@@ -130,19 +130,19 @@ static int pms_i2c_write(u16 slave, u16 sub, u16 data)
        int skip=0;
        int count;
        int i;
-       
+
        for(i=0;i<i2c_count;i++)
        {
                if((i2cinfo[i].slave==slave) &&
                   (i2cinfo[i].sub == sub))
                {
-                       if(i2cinfo[i].data==data)
-                               skip=1;
-                       i2cinfo[i].data=data;
-                       i=i2c_count+1;
+                       if(i2cinfo[i].data==data)
+                               skip=1;
+                       i2cinfo[i].data=data;
+                       i=i2c_count+1;
                }
        }
-       
+
        if(i==i2c_count && i2c_count<64)
        {
                i2cinfo[i2c_count].slave=slave;
@@ -150,16 +150,16 @@ static int pms_i2c_write(u16 slave, u16 sub, u16 data)
                i2cinfo[i2c_count].data=data;
                i2c_count++;
        }
-       
+
        if(skip)
                return 0;
-               
+
        mvv_write(0x29, sub);
        mvv_write(0x2A, data);
        mvv_write(0x28, slave);
-       
+
        outb(0x28, io_port);
-       
+
        count=0;
        while((inb(data_port)&1)==0)
                if(count>255)
@@ -167,9 +167,9 @@ static int pms_i2c_write(u16 slave, u16 sub, u16 data)
        while((inb(data_port)&1)!=0)
                if(count>255)
                        break;
-                       
+
        count=inb(data_port);
-       
+
        if(count&2)
                return -1;
        return count;
@@ -189,8 +189,8 @@ static int pms_i2c_read(int slave, int sub)
 
 static void pms_i2c_andor(int slave, int sub, int and, int or)
 {
-       u8 tmp; 
-       
+       u8 tmp;
+
        tmp=pms_i2c_read(slave, sub);
        tmp = (tmp&and)|or;
        pms_i2c_write(slave, sub, tmp);
@@ -199,7 +199,7 @@ static void pms_i2c_andor(int slave, int sub, int and, int or)
 /*
  *     Control functions
  */
+
 
 static void pms_videosource(short source)
 {
@@ -234,8 +234,8 @@ static void pms_colour(short colour)
                        break;
        }
 }
+
+
 static void pms_contrast(short contrast)
 {
        switch(decoder)
@@ -269,14 +269,14 @@ static void pms_format(short format)
 {
        int target;
        standard = format;
-       
+
        if(decoder==PHILIPS1)
                target=0x42;
        else if(decoder==PHILIPS2)
                target=0x8A;
        else
                return;
-                               
+
        switch(format)
        {
                case 0: /* Auto */
@@ -302,7 +302,7 @@ static void pms_format(short format)
 
 /*
  *     These features of the PMS card are not currently exposes. They
- *     could become a private v4l ioctl for PMSCONFIG or somesuch if 
+ *     could become a private v4l ioctl for PMSCONFIG or somesuch if
  *     people need it. We also don't yet use the PMS interrupt.
  */
 
@@ -324,7 +324,7 @@ static void pms_hstart(short start)
 /*
  *     Bandpass filters
  */
+
 static void pms_bandpass(short pass)
 {
        if(decoder==PHILIPS2)
@@ -493,7 +493,7 @@ static void pms_vert(u8 deciden, u8 decinum)
 /*
  *     Turn 16bit ratios into best small ratio the chipset can grok
  */
+
 static void pms_vertdeci(unsigned short decinum, unsigned short deciden)
 {
        /* Knock it down by /5 once */
@@ -546,7 +546,7 @@ static void pms_horzdeci(short decinum, short deciden)
                decinum=512;
                deciden=640;    /* 768 would be ideal */
        }
-       
+
        while(((decinum|deciden)&1)==0)
        {
                decinum>>=1;
@@ -559,7 +559,7 @@ static void pms_horzdeci(short decinum, short deciden)
        }
        if(deciden==32)
                deciden--;
-               
+
        mvv_write(0x24, 0x80|deciden);
        mvv_write(0x25, decinum);
 }
@@ -567,14 +567,14 @@ static void pms_horzdeci(short decinum, short deciden)
 static void pms_resolution(short width, short height)
 {
        int fg_height;
-       
+
        fg_height=height;
        if(fg_height>280)
                fg_height=280;
-               
+
        mvv_write(0x18, fg_height);
        mvv_write(0x19, fg_height>>8);
-       
+
        if(standard==1)
        {
                mvv_write(0x1A, 0xFC);
@@ -598,7 +598,7 @@ static void pms_resolution(short width, short height)
        mvv_write(0x42, 0x00);
        mvv_write(0x43, 0x00);
        mvv_write(0x44, MVVMEMORYWIDTH);
-       
+
        mvv_write(0x22, width+8);
        mvv_write(0x23, (width+8)>> 8);
 
@@ -618,7 +618,7 @@ static void pms_resolution(short width, short height)
 /*
  *     Set Input
  */
+
 static void pms_vcrinput(short input)
 {
        if(decoder==PHILIPS2)
@@ -643,20 +643,20 @@ static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int
        mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */
 
 /*     printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
-  
-       for (y = 0; y < dev->height; y++ ) 
+
+       for (y = 0; y < dev->height; y++ )
        {
                writeb(0, mem);  /* synchronisiert neue Zeile */
-               
+
                /*
                 *      This is in truth a fifo, be very careful as if you
                 *      forgot this odd things will occur 8)
                 */
-                
+
                memcpy_fromio(tmp, mem, dw+32); /* discard 16 word   */
                cnt -= dev->height;
-               while (cnt <= 0) 
-               { 
+               while (cnt <= 0)
+               {
                        /*
                         *      Don't copy too far
                         */
@@ -666,7 +666,7 @@ static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int
                        cnt += dev->height;
                        if (copy_to_user(buf, tmp+32, dt))
                                return len ? len : -EFAULT;
-                       buf += dt;    
+                       buf += dt;
                        len += dt;
                }
        }
@@ -683,7 +683,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *dev = video_devdata(file);
        struct pms_device *pd=(struct pms_device *)dev;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -806,7 +806,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                            ||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
                                return -EINVAL;
                        pd->picture= *p;
-                       
+
                        /*
                         *      Now load the card.
                         */
@@ -815,7 +815,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                        pms_brightness(p->brightness>>8);
                        pms_hue(p->hue>>8);
                        pms_colour(p->colour>>8);
-                       pms_contrast(p->contrast>>8);   
+                       pms_contrast(p->contrast>>8);
                        mutex_unlock(&pd->lock);
                        return 0;
                }
@@ -873,7 +873,7 @@ static ssize_t pms_read(struct file *file, char __user *buf,
        struct video_device *v = video_devdata(file);
        struct pms_device *pd=(struct pms_device *)v;
        int len;
-       
+
        mutex_lock(&pd->lock);
        len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
        mutex_unlock(&pd->lock);
@@ -905,13 +905,13 @@ static struct pms_device pms_device;
 /*
  *     Probe for and initialise the Mediavision PMS
  */
+
 static int init_mediavision(void)
 {
        int id;
        int idec, decst;
        int i;
-               
+
        unsigned char i2c_defs[]={
                0x4C,0x30,0x00,0xE8,
                0xB6,0xE2,0x00,0x00,
@@ -925,7 +925,7 @@ static int init_mediavision(void)
        mem = ioremap(mem_base, 0x800);
        if (!mem)
                return -ENOMEM;
-       
+
        if (!request_region(0x9A01, 1, "Mediavision PMS config"))
        {
                printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n");
@@ -941,18 +941,18 @@ static int init_mediavision(void)
        }
        outb(0xB8, 0x9A01);             /* Unlock */
        outb(io_port>>4, 0x9A01);       /* Set IO port */
-       
-       
+
+
        id=mvv_read(3);
        decst=pms_i2c_stat(0x43);
-       
+
        if(decst!=-1)
                idec=2;
        else if(pms_i2c_stat(0xb9)!=-1)
                idec=3;
        else if(pms_i2c_stat(0x8b)!=-1)
                idec=1;
-       else 
+       else
                idec=0;
 
        printk(KERN_INFO "PMS type is %d\n", idec);
@@ -966,11 +966,11 @@ static int init_mediavision(void)
        /*
         *      Ok we have a PMS of some sort
         */
-       
+
        mvv_write(0x04, mem_base>>12);  /* Set the memory area */
-       
+
        /* Ok now load the defaults */
-       
+
        for(i=0;i<0x19;i++)
        {
                if(i2c_defs[i]==0xFF)
@@ -978,7 +978,7 @@ static int init_mediavision(void)
                else
                        pms_i2c_write(0x8A, i, i2c_defs[i]);
        }
-       
+
        pms_i2c_write(0xB8,0x00,0x12);
        pms_i2c_write(0xB8,0x04,0x00);
        pms_i2c_write(0xB8,0x07,0x00);
@@ -987,18 +987,18 @@ static int init_mediavision(void)
        pms_i2c_write(0xB8,0x0A,0x00);
        pms_i2c_write(0xB8,0x0B,0x10);
        pms_i2c_write(0xB8,0x10,0x03);
-       
+
        mvv_write(0x01, 0x00);
        mvv_write(0x05, 0xA0);
        mvv_write(0x08, 0x25);
        mvv_write(0x09, 0x00);
-       mvv_write(0x0A, 0x20|MVVMEMORYWIDTH);   
-       
+       mvv_write(0x0A, 0x20|MVVMEMORYWIDTH);
+
        mvv_write(0x10, 0x02);
        mvv_write(0x1E, 0x0C);
        mvv_write(0x1F, 0x03);
        mvv_write(0x26, 0x06);
-       
+
        mvv_write(0x2B, 0x00);
        mvv_write(0x2C, 0x20);
        mvv_write(0x2D, 0x00);
@@ -1018,13 +1018,13 @@ static int init_mediavision(void)
 /*
  *     Initialization and module stuff
  */
+
 static int __init init_pms_cards(void)
 {
        printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
-       
+
        data_port = io_port +1;
-       
+
        if(init_mediavision())
        {
                printk(KERN_INFO "Board not found.\n");
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
new file mode 100644 (file)
index 0000000..8326684
--- /dev/null
@@ -0,0 +1,20 @@
+ifneq ($(KERNELRELEASE),)
+
+pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+
+obj-$(CONFIG_USB_PWC) += pwc.o
+
+else
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default:
+       $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+
+endif
+
+clean:
+       rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c
+       rm -rf .tmp_versions
+
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
new file mode 100644 (file)
index 0000000..11f751a
--- /dev/null
@@ -0,0 +1,236 @@
+This file contains some additional information for the Philips and OEM webcams.
+E-mail: webcam@smcc.demon.nl                        Last updated: 2004-01-19
+Site: http://www.smcc.demon.nl/webcam/
+
+As of this moment, the following cameras are supported:
+ * Philips PCA645
+ * Philips PCA646
+ * Philips PCVC675
+ * Philips PCVC680
+ * Philips PCVC690
+ * Philips PCVC720/40
+ * Philips PCVC730
+ * Philips PCVC740
+ * Philips PCVC750
+ * Askey VC010
+ * Creative Labs Webcam 5
+ * Creative Labs Webcam Pro Ex
+ * Logitech QuickCam 3000 Pro
+ * Logitech QuickCam 4000 Pro
+ * Logitech QuickCam Notebook Pro
+ * Logitech QuickCam Zoom
+ * Logitech QuickCam Orbit
+ * Logitech QuickCam Sphere
+ * Samsung MPC-C10
+ * Samsung MPC-C30
+ * Sotec Afina Eye
+ * AME CU-001
+ * Visionite VCS-UM100
+ * Visionite VCS-UC300
+
+The main webpage for the Philips driver is at the address above. It contains
+a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
+contains decompression routines that allow you to use higher image sizes and
+framerates; in addition the webcam uses less bandwidth on the USB bus (handy
+if you want to run more than 1 camera simultaneously). These routines fall
+under a NDA, and may therefor not be distributed as source; however, its use
+is completely optional.
+
+You can build this code either into your kernel, or as a module. I recommend
+the latter, since it makes troubleshooting a lot easier. The built-in
+microphone is supported through the USB Audio class.
+
+When you load the module you can set some default settings for the
+camera; some programs depend on a particular image-size or -format and
+don't know how to set it properly in the driver. The options are:
+
+size
+   Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
+   'vga', for an image size of resp. 128x96, 160x120, 176x144,
+   320x240, 352x288 and 640x480 (of course, only for those cameras that
+   support these resolutions).
+
+fps
+   Specifies the desired framerate. Is an integer in the range of 4-30.
+
+fbufs
+   This paramter specifies the number of internal buffers to use for storing
+   frames from the cam. This will help if the process that reads images from
+   the cam is a bit slow or momentarely busy. However, on slow machines it
+   only introduces lag, so choose carefully. The default is 3, which is
+   reasonable. You can set it between 2 and 5.
+
+mbufs
+   This is an integer between 1 and 10. It will tell the module the number of
+   buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends.
+   The default is 2, which is adequate for most applications (double
+   buffering).
+
+   Should you experience a lot of 'Dumping frame...' messages during
+   grabbing with a tool that uses mmap(), you might want to increase if.
+   However, it doesn't really buffer images, it just gives you a bit more
+   slack when your program is behind. But you need a multi-threaded or
+   forked program to really take advantage of these buffers.
+
+   The absolute maximum is 10, but don't set it too high!  Every buffer takes
+   up 460 KB of RAM, so unless you have a lot of memory setting this to
+   something more than 4 is an absolute waste.  This memory is only
+   allocated during open(), so nothing is wasted when the camera is not in
+   use.
+
+power_save
+   When power_save is enabled (set to 1), the module will try to shut down
+   the cam on close() and re-activate on open(). This will save power and
+   turn off the LED. Not all cameras support this though (the 645 and 646
+   don't have power saving at all), and some models don't work either (they
+   will shut down, but never wake up). Consider this experimental. By
+   default this option is disabled.
+
+compression (only useful with the plugin)
+   With this option you can control the compression factor that the camera
+   uses to squeeze the image through the USB bus. You can set the
+   parameter between 0 and 3:
+     0 = prefer uncompressed images; if the requested mode is not available
+        in an uncompressed format, the driver will silently switch to low
+        compression.
+     1 = low compression.
+     2 = medium compression.
+     3 = high compression.
+
+   High compression takes less bandwidth of course, but it could also
+   introduce some unwanted artefacts. The default is 2, medium compression.
+   See the FAQ on the website for an overview of which modes require
+   compression.
+
+   The compression parameter does not apply to the 645 and 646 cameras
+   and OEM models derived from those (only a few). Most cams honour this
+   parameter.
+
+leds
+   This settings takes 2 integers, that define the on/off time for the LED
+   (in milliseconds). One of the interesting things that you can do with
+   this is let the LED blink while the camera is in use. This:
+
+     leds=500,500
+
+   will blink the LED once every second. But with:
+
+     leds=0,0
+
+   the LED never goes on, making it suitable for silent surveillance.
+
+   By default the camera's LED is on solid while in use, and turned off
+   when the camera is not used anymore.
+
+   This parameter works only with the ToUCam range of cameras (720, 730, 740,
+   750) and OEMs. For other cameras this command is silently ignored, and
+   the LED cannot be controlled.
+
+   Finally: this parameters does not take effect UNTIL the first time you
+   open the camera device. Until then, the LED remains on.
+
+dev_hint
+   A long standing problem with USB devices is their dynamic nature: you
+   never know what device a camera gets assigned; it depends on module load
+   order, the hub configuration, the order in which devices are plugged in,
+   and the phase of the moon (i.e. it can be random). With this option you
+   can give the driver a hint as to what video device node (/dev/videoX) it
+   should use with a specific camera. This is also handy if you have two
+   cameras of the same model.
+
+   A camera is specified by its type (the number from the camera model,
+   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
+   in /proc/bus/usb/devices). A hint consists of a string with the following
+   format:
+
+      [type[.serialnumber]:]node
+
+   The square brackets mean that both the type and the serialnumber are
+   optional, but a serialnumber cannot be specified without a type (which
+   would be rather pointless). The serialnumber is separated from the type
+   by a '.'; the node number by a ':'.
+
+   This somewhat cryptic syntax is best explained by a few examples:
+
+     dev_hint=3,5              The first detected cam gets assigned
+                              /dev/video3, the second /dev/video5. Any
+                              other cameras will get the first free
+                              available slot (see below).
+
+     dev_hint=645:1,680:2      The PCA645 camera will get /dev/video1,
+                              and a PCVC680 /dev/video2.
+
+     dev_hint=645.0123:3,645.4567:0    The PCA645 camera with serialnumber
+                                       0123 goes to /dev/video3, the same
+                                       camera model with the 4567 serial
+                                       gets /dev/video0.
+
+     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the
+                               next 3 Philips cams will use /dev/video4
+                               through /dev/video6.
+
+   Some points worth knowing:
+   - Serialnumbers are case sensitive and must be written full, including
+     leading zeroes (it's treated as a string).
+   - If a device node is already occupied, registration will fail and
+     the webcam is not available.
+   - You can have up to 64 video devices; be sure to make enough device
+     nodes in /dev if you want to spread the numbers (this does not apply
+     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
+   - If a camera does not match any dev_hint, it will simply get assigned
+     the first available device node, just as it used to be.
+
+trace
+   In order to better detect problems, it is now possible to turn on a
+   'trace' of some of the calls the module makes; it logs all items in your
+   kernel log at debug level.
+
+   The trace variable is a bitmask; each bit represents a certain feature.
+   If you want to trace something, look up the bit value(s) in the table
+   below, add the values together and supply that to the trace variable.
+
+   Value  Value   Description                                     Default
+   (dec)  (hex)
+       1    0x1   Module initialization; this will log messages       On
+                 while loading and unloading the module
+
+       2    0x2   probe() and disconnect() traces                     On
+
+       4    0x4   Trace open() and close() calls                      Off
+
+       8    0x8   read(), mmap() and associated ioctl() calls         Off
+
+      16   0x10   Memory allocation of buffers, etc.                  Off
+
+      32   0x20   Showing underflow, overflow and Dumping frame       On
+                 messages
+
+      64   0x40   Show viewport and image sizes                       Off
+
+     128   0x80   PWCX debugging                                      Off
+
+   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+   so you would supply trace=12 during insmod or modprobe. If
+   you want to turn the initialization and probing tracing off, set trace=0.
+   The default value for trace is 35 (0x23).
+
+
+
+Example:
+
+     # modprobe pwc size=cif fps=15 power_save=1
+
+The fbufs, mbufs and trace parameters are global and apply to all connected
+cameras. Each camera has its own set of buffers.
+
+size and fps only specify defaults when you open() the device; this is to
+accommodate some tools that don't set the size. You can change these
+settings after open() with the Video4Linux ioctl() calls. The default of
+defaults is QCIF size at 10 fps.
+
+The compression parameter is semiglobal; it sets the initial compression
+preference for all camera's, but this parameter can be set per camera with
+the VIDIOCPWCSCQUAL ioctl() call.
+
+All parameters are optional.
+
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
new file mode 100644 (file)
index 0000000..4ba549b
--- /dev/null
@@ -0,0 +1,1541 @@
+/* Driver for Philips webcam
+   Functions that send various control messages to the webcam, including
+   video modes.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added methods for changing white balance and
+                         red/green gains
+ */
+
+/* Control functions for the cam; brightness, contrast, video mode, etc. */
+
+#ifdef __KERNEL__
+#include <asm/uaccess.h>
+#endif
+#include <asm/errno.h>
+
+#include "pwc.h"
+#include "pwc-ioctl.h"
+#include "pwc-uncompress.h"
+#include "pwc-kiara.h"
+#include "pwc-timon.h"
+
+/* Request types: video */
+#define SET_LUM_CTL                    0x01
+#define GET_LUM_CTL                    0x02
+#define SET_CHROM_CTL                  0x03
+#define GET_CHROM_CTL                  0x04
+#define SET_STATUS_CTL                 0x05
+#define GET_STATUS_CTL                 0x06
+#define SET_EP_STREAM_CTL              0x07
+#define GET_EP_STREAM_CTL              0x08
+#define SET_MPT_CTL                    0x0D
+#define GET_MPT_CTL                    0x0E
+
+/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
+#define AGC_MODE_FORMATTER                     0x2000
+#define PRESET_AGC_FORMATTER                   0x2100
+#define SHUTTER_MODE_FORMATTER                 0x2200
+#define PRESET_SHUTTER_FORMATTER               0x2300
+#define PRESET_CONTOUR_FORMATTER               0x2400
+#define AUTO_CONTOUR_FORMATTER                 0x2500
+#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
+#define CONTRAST_FORMATTER                     0x2700
+#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
+#define FLICKERLESS_MODE_FORMATTER             0x2900
+#define AE_CONTROL_SPEED                       0x2A00
+#define BRIGHTNESS_FORMATTER                   0x2B00
+#define GAMMA_FORMATTER                                0x2C00
+
+/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
+#define WB_MODE_FORMATTER                      0x1000
+#define AWB_CONTROL_SPEED_FORMATTER            0x1100
+#define AWB_CONTROL_DELAY_FORMATTER            0x1200
+#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
+#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
+#define COLOUR_MODE_FORMATTER                  0x1500
+#define SATURATION_MODE_FORMATTER1             0x1600
+#define SATURATION_MODE_FORMATTER2             0x1700
+
+/* Selectors for the Status controls [GS]ET_STATUS_CTL */
+#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
+#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
+#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
+#define READ_AGC_FORMATTER                     0x0500
+#define READ_SHUTTER_FORMATTER                 0x0600
+#define READ_RED_GAIN_FORMATTER                        0x0700
+#define READ_BLUE_GAIN_FORMATTER               0x0800
+#define SENSOR_TYPE_FORMATTER1                 0x0C00
+#define READ_RAW_Y_MEAN_FORMATTER              0x3100
+#define SET_POWER_SAVE_MODE_FORMATTER          0x3200
+#define MIRROR_IMAGE_FORMATTER                 0x3300
+#define LED_FORMATTER                          0x3400
+#define SENSOR_TYPE_FORMATTER2                 0x3700
+
+/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
+#define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
+
+/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
+#define PT_RELATIVE_CONTROL_FORMATTER          0x01
+#define PT_RESET_CONTROL_FORMATTER             0x02
+#define PT_STATUS_FORMATTER                    0x03
+
+static const char *size2name[PSZ_MAX] =
+{
+       "subQCIF",
+       "QSIF",
+       "QCIF",
+       "SIF",
+       "CIF",
+       "VGA",
+};
+
+/********/
+
+/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
+   preferences, so you either get compressed or non-compressed streams.
+
+   An alternate value of 0 means this mode is not available at all.
+ */
+
+struct Nala_table_entry {
+       char alternate;                 /* USB alternate setting */
+       int compressed;                 /* Compressed yes/no */
+
+       unsigned char mode[3];          /* precomputed mode table */
+};
+
+static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
+{
+#include "pwc-nala.h"
+};
+
+
+/****************************************************************************/
+
+
+#define SendControlMsg(request, value, buflen) \
+       usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
+               request, \
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+               value, \
+               pdev->vcinterface, \
+               &buf, buflen, 500)
+
+#define RecvControlMsg(request, value, buflen) \
+       usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
+               request, \
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+               value, \
+               pdev->vcinterface, \
+               &buf, buflen, 500)
+
+
+#if PWC_DEBUG
+void pwc_hexdump(void *p, int len)
+{
+       int i;
+       unsigned char *s;
+       char buf[100], *d;
+
+       s = (unsigned char *)p;
+       d = buf;
+       *d = '\0';
+       Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
+       for (i = 0; i < len; i++) {
+               d += sprintf(d, "%02X ", *s++);
+               if ((i & 0xF) == 0xF) {
+                       Debug("%s\n", buf);
+                       d = buf;
+                       *d = '\0';
+               }
+       }
+       if ((i & 0xF) != 0)
+               Debug("%s\n", buf);
+}
+#endif
+
+static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+{
+       return usb_control_msg(udev,
+               usb_sndctrlpipe(udev, 0),
+               SET_EP_STREAM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               VIDEO_OUTPUT_CONTROL_FORMATTER,
+               index,
+               buf, buflen, 1000);
+}
+
+
+
+static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+{
+       unsigned char buf[3];
+       int ret, fps;
+       struct Nala_table_entry *pEntry;
+       int frames2frames[31] =
+       { /* closest match of framerate */
+          0,  0,  0,  0,  4,  /*  0-4  */
+          5,  5,  7,  7, 10,  /*  5-9  */
+         10, 10, 12, 12, 15,  /* 10-14 */
+         15, 15, 15, 20, 20,  /* 15-19 */
+         20, 20, 20, 24, 24,  /* 20-24 */
+         24, 24, 24, 24, 24,  /* 25-29 */
+         24                   /* 30    */
+       };
+       int frames2table[31] =
+       { 0, 0, 0, 0, 0, /*  0-4  */
+         1, 1, 1, 2, 2, /*  5-9  */
+         3, 3, 4, 4, 4, /* 10-14 */
+         5, 5, 5, 5, 5, /* 15-19 */
+         6, 6, 6, 6, 7, /* 20-24 */
+         7, 7, 7, 7, 7, /* 25-29 */
+         7              /* 30    */
+       };
+
+       if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
+               return -EINVAL;
+       frames = frames2frames[frames];
+       fps = frames2table[frames];
+       pEntry = &Nala_table[size][fps];
+       if (pEntry->alternate == 0)
+               return -EINVAL;
+
+       if (pEntry->compressed)
+               return -ENOENT; /* Not supported. */
+
+       memcpy(buf, pEntry->mode, 3);
+       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
+       if (ret < 0) {
+               Debug("Failed to send video command... %d\n", ret);
+               return ret;
+       }
+       if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
+        {
+          switch(pdev->type) {
+            case 645:
+            case 646:
+/*            pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+              break;
+
+            case 675:
+            case 680:
+            case 690:
+            case 720:
+            case 730:
+            case 740:
+            case 750:
+/*            pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+              break;
+          }
+       }
+
+       pdev->cmd_len = 3;
+       memcpy(pdev->cmd_buf, buf, 3);
+
+       /* Set various parameters */
+       pdev->vframes = frames;
+       pdev->vsize = size;
+       pdev->valternate = pEntry->alternate;
+       pdev->image = pwc_image_sizes[size];
+       pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
+       if (pEntry->compressed) {
+               if (pdev->release < 5) { /* 4 fold compression */
+                       pdev->vbandlength = 528;
+                       pdev->frame_size /= 4;
+               }
+               else {
+                       pdev->vbandlength = 704;
+                       pdev->frame_size /= 3;
+               }
+       }
+       else
+               pdev->vbandlength = 0;
+       return 0;
+}
+
+
+static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+{
+       unsigned char buf[13];
+       const struct Timon_table_entry *pChoose;
+       int ret, fps;
+
+       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
+               return -EINVAL;
+       if (size == PSZ_VGA && frames > 15)
+               return -EINVAL;
+       fps = (frames / 5) - 1;
+
+       /* Find a supported framerate with progressively higher compression ratios
+          if the preferred ratio is not available.
+       */
+       pChoose = NULL;
+       while (compression <= 3) {
+          pChoose = &Timon_table[size][fps][compression];
+          if (pChoose->alternate != 0)
+            break;
+          compression++;
+       }
+       if (pChoose == NULL || pChoose->alternate == 0)
+               return -ENOENT; /* Not supported. */
+
+       memcpy(buf, pChoose->mode, 13);
+       if (snapshot)
+               buf[0] |= 0x80;
+       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
+       if (ret < 0)
+               return ret;
+
+/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+          pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+
+       pdev->cmd_len = 13;
+       memcpy(pdev->cmd_buf, buf, 13);
+
+       /* Set various parameters */
+       pdev->vframes = frames;
+       pdev->vsize = size;
+       pdev->vsnapshot = snapshot;
+       pdev->valternate = pChoose->alternate;
+       pdev->image = pwc_image_sizes[size];
+       pdev->vbandlength = pChoose->bandlength;
+       if (pChoose->bandlength > 0)
+               pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
+       else
+               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+       return 0;
+}
+
+
+static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+{
+       const struct Kiara_table_entry *pChoose = NULL;
+       int fps, ret;
+       unsigned char buf[12];
+       struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
+
+       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
+               return -EINVAL;
+       if (size == PSZ_VGA && frames > 15)
+               return -EINVAL;
+       fps = (frames / 5) - 1;
+
+       /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
+       if (size == PSZ_VGA && frames == 5 && snapshot)
+       {
+               /* Only available in case the raw palette is selected or
+                  we have the decompressor available. This mode is
+                  only available in compressed form
+               */
+               if (pdev->vpalette == VIDEO_PALETTE_RAW)
+               {
+                       Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
+                       pChoose = &RawEntry;
+               }
+               else
+               {
+                       Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
+               }
+       }
+       else
+       {
+               /* Find a supported framerate with progressively higher compression ratios
+                  if the preferred ratio is not available.
+                  Skip this step when using RAW modes.
+               */
+               while (compression <= 3) {
+                       pChoose = &Kiara_table[size][fps][compression];
+                       if (pChoose->alternate != 0)
+                               break;
+                       compression++;
+               }
+       }
+       if (pChoose == NULL || pChoose->alternate == 0)
+               return -ENOENT; /* Not supported. */
+
+       Debug("Using alternate setting %d.\n", pChoose->alternate);
+
+       /* usb_control_msg won't take staticly allocated arrays as argument?? */
+       memcpy(buf, pChoose->mode, 12);
+       if (snapshot)
+               buf[0] |= 0x80;
+
+       /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
+       ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
+       if (ret < 0)
+               return ret;
+
+/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+         pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+
+       pdev->cmd_len = 12;
+       memcpy(pdev->cmd_buf, buf, 12);
+       /* All set and go */
+       pdev->vframes = frames;
+       pdev->vsize = size;
+       pdev->vsnapshot = snapshot;
+       pdev->valternate = pChoose->alternate;
+       pdev->image = pwc_image_sizes[size];
+       pdev->vbandlength = pChoose->bandlength;
+       if (pdev->vbandlength > 0)
+               pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
+       else
+               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+       return 0;
+}
+
+
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+       int i, factor = 0, filler = 0;
+
+       /* for PALETTE_YUV420P */
+       switch(pdev->vpalette)
+       {
+       case VIDEO_PALETTE_YUV420P:
+               factor = 6;
+               filler = 128;
+               break;
+       case VIDEO_PALETTE_RAW:
+               factor = 6; /* can be uncompressed YUV420P */
+               filler = 0;
+               break;
+       }
+
+       /* Set sizes in bytes */
+       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
+
+       /* Align offset, or you'll get some very weird results in
+          YUV420 mode... x must be multiple of 4 (to get the Y's in
+          place), and y even (or you'll mixup U & V). This is less of a
+          problem for YUV420P.
+        */
+       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+       /* Fill buffers with gray or black */
+       for (i = 0; i < MAX_IMAGES; i++) {
+               if (pdev->image_ptr[i] != NULL)
+                       memset(pdev->image_ptr[i], filler, pdev->view.size);
+       }
+}
+
+
+
+/**
+   @pdev: device structure
+   @width: viewport width
+   @height: viewport height
+   @frame: framerate, in fps
+   @compression: preferred compression ratio
+   @snapshot: snapshot mode or streaming
+ */
+int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
+{
+       int ret, size;
+
+       Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+       size = pwc_decode_size(pdev, width, height);
+       if (size < 0) {
+               Debug("Could not find suitable size.\n");
+               return -ERANGE;
+       }
+       Debug("decode_size = %d.\n", size);
+
+       ret = -EINVAL;
+       switch(pdev->type) {
+       case 645:
+       case 646:
+               ret = set_video_mode_Nala(pdev, size, frames);
+               break;
+
+       case 675:
+       case 680:
+       case 690:
+               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
+               break;
+
+       case 720:
+       case 730:
+       case 740:
+       case 750:
+               ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
+               break;
+       }
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
+               else {
+                       Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
+               }
+               return ret;
+       }
+       pdev->view.x = width;
+       pdev->view.y = height;
+       pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
+       pwc_set_image_buffer_size(pdev);
+       Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+       return 0;
+}
+
+
+/* BRIGHTNESS */
+
+int pwc_get_brightness(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return buf << 9;
+}
+
+int pwc_set_brightness(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       buf = (value >> 9) & 0x7f;
+       return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
+}
+
+/* CONTRAST */
+
+int pwc_get_contrast(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return buf << 10;
+}
+
+int pwc_set_contrast(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       buf = (value >> 10) & 0x3f;
+       return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1);
+}
+
+/* GAMMA */
+
+int pwc_get_gamma(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return buf << 11;
+}
+
+int pwc_set_gamma(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       buf = (value >> 11) & 0x1f;
+       return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1);
+}
+
+
+/* SATURATION */
+
+int pwc_get_saturation(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       if (pdev->type < 675)
+               return -1;
+       ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+       if (ret < 0)
+               return ret;
+       return 32768 + buf * 327;
+}
+
+int pwc_set_saturation(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (pdev->type < 675)
+               return -EINVAL;
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       /* saturation ranges from -100 to +100 */
+       buf = (value - 32768) / 327;
+       return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+}
+
+/* AGC */
+
+static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+{
+       char buf;
+       int ret;
+
+       if (mode)
+               buf = 0x0; /* auto */
+       else
+               buf = 0xff; /* fixed */
+
+       ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1);
+
+       if (!mode && ret >= 0) {
+               if (value < 0)
+                       value = 0;
+               if (value > 0xffff)
+                       value = 0xffff;
+               buf = (value >> 10) & 0x3F;
+               ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
+       }
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+
+       if (buf != 0) { /* fixed */
+               ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
+               if (ret < 0)
+                       return ret;
+               if (buf > 0x3F)
+                       buf = 0x3F;
+               *value = (buf << 10);
+       }
+       else { /* auto */
+               ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1);
+               if (ret < 0)
+                       return ret;
+               /* Gah... this value ranges from 0x00 ... 0x9F */
+               if (buf > 0x9F)
+                       buf = 0x9F;
+               *value = -(48 + buf * 409);
+       }
+
+       return 0;
+}
+
+static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+{
+       char buf[2];
+       int speed, ret;
+
+
+       if (mode)
+               buf[0] = 0x0;   /* auto */
+       else
+               buf[0] = 0xff; /* fixed */
+
+       ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1);
+
+       if (!mode && ret >= 0) {
+               if (value < 0)
+                       value = 0;
+               if (value > 0xffff)
+                       value = 0xffff;
+               switch(pdev->type) {
+               case 675:
+               case 680:
+               case 690:
+                       /* speed ranges from 0x0 to 0x290 (656) */
+                       speed = (value / 100);
+                       buf[1] = speed >> 8;
+                       buf[0] = speed & 0xff;
+                       break;
+               case 720:
+               case 730:
+               case 740:
+               case 750:
+                       /* speed seems to range from 0x0 to 0xff */
+                       buf[1] = 0;
+                       buf[0] = value >> 8;
+                       break;
+               }
+
+               ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
+       }
+       return ret;
+}
+
+
+/* POWER */
+
+int pwc_camera_power(struct pwc_device *pdev, int power)
+{
+       char buf;
+
+       if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
+               return 0;       /* Not supported by Nala or Timon < release 6 */
+
+       if (power)
+               buf = 0x00; /* active */
+       else
+               buf = 0xFF; /* power save */
+       return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1);
+}
+
+
+
+/* private calls */
+
+static inline int pwc_restore_user(struct pwc_device *pdev)
+{
+       char buf; /* dummy */
+       return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
+}
+
+static inline int pwc_save_user(struct pwc_device *pdev)
+{
+       char buf; /* dummy */
+       return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
+}
+
+static inline int pwc_restore_factory(struct pwc_device *pdev)
+{
+       char buf; /* dummy */
+       return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
+}
+
+ /* ************************************************* */
+ /* Patch by Alvarado: (not in the original version   */
+
+ /*
+  * the camera recognizes modes from 0 to 4:
+  *
+  * 00: indoor (incandescant lighting)
+  * 01: outdoor (sunlight)
+  * 02: fluorescent lighting
+  * 03: manual
+  * 04: auto
+  */
+static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+{
+       char buf;
+       int ret;
+
+       if (mode < 0)
+           mode = 0;
+
+       if (mode > 4)
+           mode = 4;
+
+       buf = mode & 0x07; /* just the lowest three bits */
+
+       ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1);
+
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int pwc_get_awb(struct pwc_device *pdev)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1);
+
+       if (ret < 0)
+               return ret;
+       return buf;
+}
+
+static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+{
+       unsigned char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       /* only the msb is considered */
+       buf = value >> 8;
+       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
+}
+
+static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
+       if (ret < 0)
+           return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+
+static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+{
+       unsigned char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       /* only the msb is considered */
+       buf = value >> 8;
+       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
+}
+
+static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
+       if (ret < 0)
+           return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+
+/* The following two functions are different, since they only read the
+   internal red/blue gains, which may be different from the manual
+   gains set or read above.
+ */
+static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+
+static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+{
+       unsigned char buf;
+
+       /* useful range is 0x01..0x20 */
+       buf = speed / 0x7f0;
+       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
+}
+
+static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf * 0x7f0;
+       return 0;
+}
+
+
+static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+{
+       unsigned char buf;
+
+       /* useful range is 0x01..0x3F */
+       buf = (delay >> 10);
+       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
+}
+
+static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf << 10;
+       return 0;
+}
+
+
+int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
+{
+       unsigned char buf[2];
+
+       if (pdev->type < 730)
+               return 0;
+       on_value /= 100;
+       off_value /= 100;
+       if (on_value < 0)
+               on_value = 0;
+       if (on_value > 0xff)
+               on_value = 0xff;
+       if (off_value < 0)
+               off_value = 0;
+       if (off_value > 0xff)
+               off_value = 0xff;
+
+       buf[0] = on_value;
+       buf[1] = off_value;
+
+       return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
+}
+
+static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
+{
+       unsigned char buf[2];
+       int ret;
+
+       if (pdev->type < 730) {
+               *on_value = -1;
+               *off_value = -1;
+               return 0;
+       }
+
+       ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
+       if (ret < 0)
+               return ret;
+       *on_value = buf[0] * 100;
+       *off_value = buf[1] * 100;
+       return 0;
+}
+
+static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+{
+       unsigned char buf;
+       int ret;
+
+       if (contour < 0)
+               buf = 0xff; /* auto contour on */
+       else
+               buf = 0x0; /* auto contour off */
+       ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+
+       if (contour < 0)
+               return 0;
+       if (contour > 0xffff)
+               contour = 0xffff;
+
+       buf = (contour >> 10); /* contour preset is [0..3f] */
+       ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+
+       if (buf == 0) {
+               /* auto mode off, query current preset value */
+               ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
+               if (ret < 0)
+                       return ret;
+               *contour = buf << 10;
+       }
+       else
+               *contour = -1;
+       return 0;
+}
+
+
+static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+{
+       unsigned char buf;
+
+       if (backlight)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
+}
+
+static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+{
+       int ret;
+       unsigned char buf;
+
+       ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *backlight = buf;
+       return 0;
+}
+
+
+static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+{
+       unsigned char buf;
+
+       if (flicker)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+}
+
+static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+{
+       int ret;
+       unsigned char buf;
+
+       ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *flicker = buf;
+       return 0;
+}
+
+
+static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+{
+       unsigned char buf;
+
+       if (noise < 0)
+               noise = 0;
+       if (noise > 3)
+               noise = 3;
+       buf = noise;
+       return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+{
+       int ret;
+       unsigned char buf;
+
+       ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *noise = buf;
+       return 0;
+}
+
+static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+       unsigned char buf;
+
+       buf = flags & 0x03; // only lower two bits are currently used
+       return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+       unsigned char buf[4];
+
+       /* set new relative angle; angles are expressed in degrees * 100,
+          but cam as .5 degree resolution, hence divide by 200. Also
+          the angle must be multiplied by 64 before it's send to
+          the cam (??)
+        */
+       pan  =  64 * pan  / 100;
+       tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
+       buf[0] = pan & 0xFF;
+       buf[1] = (pan >> 8) & 0xFF;
+       buf[2] = tilt & 0xFF;
+       buf[3] = (tilt >> 8) & 0xFF;
+       return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
+}
+
+static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+{
+       int ret;
+       unsigned char buf[5];
+
+       ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5);
+       if (ret < 0)
+               return ret;
+       status->status = buf[0] & 0x7; // 3 bits are used for reporting
+       status->time_pan = (buf[1] << 8) + buf[2];
+       status->time_tilt = (buf[3] << 8) + buf[4];
+       return 0;
+}
+
+
+int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
+{
+       unsigned char buf;
+       int ret = -1, request;
+
+       if (pdev->type < 675)
+               request = SENSOR_TYPE_FORMATTER1;
+       else if (pdev->type < 730)
+               return -1; /* The Vesta series doesn't have this call */
+       else
+               request = SENSOR_TYPE_FORMATTER2;
+
+       ret = RecvControlMsg(GET_STATUS_CTL, request, 1);
+       if (ret < 0)
+               return ret;
+       if (pdev->type < 675)
+               *sensor = buf | 0x100;
+       else
+               *sensor = buf;
+       return 0;
+}
+
+
+ /* End of Add-Ons                                    */
+ /* ************************************************* */
+
+
+int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
+{
+       int ret = 0;
+
+       switch(cmd) {
+       case VIDIOCPWCRUSER:
+       {
+               if (pwc_restore_user(pdev))
+                       ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOCPWCSUSER:
+       {
+               if (pwc_save_user(pdev))
+                       ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOCPWCFACTORY:
+       {
+               if (pwc_restore_factory(pdev))
+                       ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOCPWCSCQUAL:
+       {
+               int *qual = arg;
+
+               if (*qual < 0 || *qual > 3)
+                       ret = -EINVAL;
+               else
+                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+               if (ret >= 0)
+                       pdev->vcompression = *qual;
+               break;
+       }
+
+       case VIDIOCPWCGCQUAL:
+       {
+               int *qual = arg;
+               *qual = pdev->vcompression;
+               break;
+       }
+
+       case VIDIOCPWCPROBE:
+       {
+               struct pwc_probe *probe = arg;
+               strcpy(probe->name, pdev->vdev->name);
+               probe->type = pdev->type;
+               break;
+       }
+
+       case VIDIOCPWCGSERIAL:
+       {
+               struct pwc_serial *serial = arg;
+               strcpy(serial->serial, pdev->serial);
+               break;
+       }
+
+       case VIDIOCPWCSAGC:
+       {
+               int *agc = arg;
+               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+                       ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOCPWCGAGC:
+       {
+               int *agc = arg;
+
+               if (pwc_get_agc(pdev, agc))
+                       ret = -EINVAL;
+               break;
+       }
+
+       case VIDIOCPWCSSHUTTER:
+       {
+               int *shutter_speed = arg;
+               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+               break;
+       }
+
+       case VIDIOCPWCSAWB:
+       {
+               struct pwc_whitebalance *wb = arg;
+
+               ret = pwc_set_awb(pdev, wb->mode);
+               if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
+                       pwc_set_red_gain(pdev, wb->manual_red);
+                       pwc_set_blue_gain(pdev, wb->manual_blue);
+               }
+               break;
+       }
+
+       case VIDIOCPWCGAWB:
+       {
+               struct pwc_whitebalance *wb = arg;
+
+               memset(wb, 0, sizeof(struct pwc_whitebalance));
+               wb->mode = pwc_get_awb(pdev);
+               if (wb->mode < 0)
+                       ret = -EINVAL;
+               else {
+                       if (wb->mode == PWC_WB_MANUAL) {
+                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
+                               if (ret < 0)
+                                       break;
+                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+                               if (ret < 0)
+                                       break;
+                       }
+                       if (wb->mode == PWC_WB_AUTO) {
+                               ret = pwc_read_red_gain(pdev, &wb->read_red);
+                               if (ret < 0)
+                                       break;
+                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+                               if (ret < 0)
+                                       break;
+                       }
+               }
+               break;
+       }
+
+       case VIDIOCPWCSAWBSPEED:
+       {
+               struct pwc_wb_speed *wbs = arg;
+
+               if (wbs->control_speed > 0) {
+                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+               }
+               if (wbs->control_delay > 0) {
+                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+               }
+               break;
+       }
+
+       case VIDIOCPWCGAWBSPEED:
+       {
+               struct pwc_wb_speed *wbs = arg;
+
+               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+               if (ret < 0)
+                       break;
+               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+               if (ret < 0)
+                       break;
+               break;
+       }
+
+       case VIDIOCPWCSLED:
+       {
+               struct pwc_leds *leds = arg;
+               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
+               break;
+       }
+
+
+       case VIDIOCPWCGLED:
+       {
+               struct pwc_leds *leds = arg;
+               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+               break;
+       }
+
+       case VIDIOCPWCSCONTOUR:
+       {
+               int *contour = arg;
+               ret = pwc_set_contour(pdev, *contour);
+               break;
+       }
+
+       case VIDIOCPWCGCONTOUR:
+       {
+               int *contour = arg;
+               ret = pwc_get_contour(pdev, contour);
+               break;
+       }
+
+       case VIDIOCPWCSBACKLIGHT:
+       {
+               int *backlight = arg;
+               ret = pwc_set_backlight(pdev, *backlight);
+               break;
+       }
+
+       case VIDIOCPWCGBACKLIGHT:
+       {
+               int *backlight = arg;
+               ret = pwc_get_backlight(pdev, backlight);
+               break;
+       }
+
+       case VIDIOCPWCSFLICKER:
+       {
+               int *flicker = arg;
+               ret = pwc_set_flicker(pdev, *flicker);
+               break;
+       }
+
+       case VIDIOCPWCGFLICKER:
+       {
+               int *flicker = arg;
+               ret = pwc_get_flicker(pdev, flicker);
+               break;
+       }
+
+       case VIDIOCPWCSDYNNOISE:
+       {
+               int *dynnoise = arg;
+               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+               break;
+       }
+
+       case VIDIOCPWCGDYNNOISE:
+       {
+               int *dynnoise = arg;
+               ret = pwc_get_dynamic_noise(pdev, dynnoise);
+               break;
+       }
+
+       case VIDIOCPWCGREALSIZE:
+       {
+               struct pwc_imagesize *size = arg;
+               size->width = pdev->image.x;
+               size->height = pdev->image.y;
+               break;
+       }
+
+       case VIDIOCPWCMPTRESET:
+       {
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       int *flags = arg;
+
+                       ret = pwc_mpt_reset(pdev, *flags);
+                       if (ret >= 0)
+                       {
+                               pdev->pan_angle = 0;
+                               pdev->tilt_angle = 0;
+                       }
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCMPTGRANGE:
+       {
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_range *range = arg;
+                       *range = pdev->angle_range;
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCMPTSANGLE:
+       {
+               int new_pan, new_tilt;
+
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_angles *angles = arg;
+                       /* The camera can only set relative angles, so
+                          do some calculations when getting an absolute angle .
+                        */
+                       if (angles->absolute)
+                       {
+                               new_pan  = angles->pan;
+                               new_tilt = angles->tilt;
+                       }
+                       else
+                       {
+                               new_pan  = pdev->pan_angle  + angles->pan;
+                               new_tilt = pdev->tilt_angle + angles->tilt;
+                       }
+                       /* check absolute ranges */
+                       if (new_pan  < pdev->angle_range.pan_min  ||
+                           new_pan  > pdev->angle_range.pan_max  ||
+                           new_tilt < pdev->angle_range.tilt_min ||
+                           new_tilt > pdev->angle_range.tilt_max)
+                       {
+                               ret = -ERANGE;
+                       }
+                       else
+                       {
+                               /* go to relative range, check again */
+                               new_pan  -= pdev->pan_angle;
+                               new_tilt -= pdev->tilt_angle;
+                               /* angles are specified in degrees * 100, thus the limit = 36000 */
+                               if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
+                                       ret = -ERANGE;
+                       }
+                       if (ret == 0) /* no errors so far */
+                       {
+                               ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
+                               if (ret >= 0)
+                               {
+                                       pdev->pan_angle  += new_pan;
+                                       pdev->tilt_angle += new_tilt;
+                               }
+                               if (ret == -EPIPE) /* stall -> out of range */
+                                       ret = -ERANGE;
+                       }
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCMPTGANGLE:
+       {
+
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_angles *angles = arg;
+
+                       angles->absolute = 1;
+                       angles->pan  = pdev->pan_angle;
+                       angles->tilt = pdev->tilt_angle;
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCMPTSTATUS:
+       {
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_status *status = arg;
+                       ret = pwc_mpt_get_status(pdev, status);
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCGVIDCMD:
+       {
+               struct pwc_video_command *cmd = arg;
+
+               cmd->type = pdev->type;
+               cmd->release = pdev->release;
+               cmd->command_len = pdev->cmd_len;
+               memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
+               cmd->bandlength = pdev->vbandlength;
+               cmd->frame_size = pdev->frame_size;
+               break;
+       }
+       /*
+       case VIDIOCPWCGVIDTABLE:
+       {
+               struct pwc_table_init_buffer *table = arg;
+               table->len = pdev->cmd_len;
+               memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+               break;
+       }
+       */
+
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+
+       if (ret > 0)
+               return 0;
+       return ret;
+}
+
+
+
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
new file mode 100644 (file)
index 0000000..4141829
--- /dev/null
@@ -0,0 +1,2205 @@
+/* Linux driver for Philips webcam
+   USB and Video4Linux interface part.
+   (C) 1999-2004 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*
+   This code forms the interface between the USB layers and the Philips
+   specific stuff. Some adanved stuff of the driver falls under an
+   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
+   is thus not distributed in source form. The binary pwcx.o module
+   contains the code that falls under the NDA.
+
+   In case you're wondering: 'pwc' stands for "Philips WebCam", but
+   I really didn't want to type 'philips_web_cam' every time (I'm lazy as
+   any Linux kernel hacker, but I don't like uncomprehensible abbreviations
+   without explanation).
+
+   Oh yes, convention: to disctinguish between all the various pointers to
+   device-structures, I use these names for the pointer variables:
+   udev: struct usb_device *
+   vdev: struct video_device *
+   pdev: struct pwc_devive *
+*/
+
+/* Contributors:
+   - Alvarado: adding whitebalance code
+   - Alistar Moire: QuickCam 3000 Pro device/product ID
+   - Tony Hoyle: Creative Labs Webcam 5 device/product ID
+   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
+   - Jk Fang: Sotec Afina Eye ID
+   - Xavier Roche: QuickCam Pro 4000 ID
+   - Jens Knudsen: QuickCam Zoom ID
+   - J. Debert: QuickCam for Notebooks ID
+*/
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+#include "pwc-ioctl.h"
+#include "pwc-kiara.h"
+#include "pwc-timon.h"
+#include "pwc-uncompress.h"
+
+/* Function prototypes and driver templates */
+
+/* hotplug device table support */
+static struct usb_device_id pwc_device_table [] = {
+       { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
+       { USB_DEVICE(0x0471, 0x0303) },
+       { USB_DEVICE(0x0471, 0x0304) },
+       { USB_DEVICE(0x0471, 0x0307) },
+       { USB_DEVICE(0x0471, 0x0308) },
+       { USB_DEVICE(0x0471, 0x030C) },
+       { USB_DEVICE(0x0471, 0x0310) },
+       { USB_DEVICE(0x0471, 0x0311) },
+       { USB_DEVICE(0x0471, 0x0312) },
+       { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+       { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
+       { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
+       { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
+       { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
+       { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
+       { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
+       { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
+       { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
+       { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
+       { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
+       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
+       { USB_DEVICE(0x055D, 0x9001) },
+       { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
+       { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
+       { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
+       { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
+       { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
+       { USB_DEVICE(0x0d81, 0x1900) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, pwc_device_table);
+
+static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void usb_pwc_disconnect(struct usb_interface *intf);
+
+static struct usb_driver pwc_driver = {
+       .name =                 "Philips webcam",       /* name */
+       .id_table =             pwc_device_table,
+       .probe =                usb_pwc_probe,          /* probe() */
+       .disconnect =           usb_pwc_disconnect,     /* disconnect() */
+};
+
+#define MAX_DEV_HINTS  20
+#define MAX_ISOC_ERRORS        20
+
+static int default_size = PSZ_QCIF;
+static int default_fps = 10;
+static int default_fbufs = 3;   /* Default number of frame buffers */
+static int default_mbufs = 2;  /* Default number of mmap() buffers */
+       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+static int power_save = 0;
+static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
+static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static struct {
+       int type;
+       char serial_number[30];
+       int device_node;
+       struct pwc_device *pdev;
+} device_hint[MAX_DEV_HINTS];
+
+/***/
+
+static int pwc_video_open(struct inode *inode, struct file *file);
+static int pwc_video_close(struct inode *inode, struct file *file);
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
+                         size_t count, loff_t *ppos);
+static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
+static int  pwc_video_ioctl(struct inode *inode, struct file *file,
+                           unsigned int ioctlnr, unsigned long arg);
+static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
+
+static struct file_operations pwc_fops = {
+       .owner =        THIS_MODULE,
+       .open =         pwc_video_open,
+       .release =      pwc_video_close,
+       .read =         pwc_video_read,
+       .poll =         pwc_video_poll,
+       .mmap =         pwc_video_mmap,
+       .ioctl =        pwc_video_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+static struct video_device pwc_template = {
+       .owner =        THIS_MODULE,
+       .name =         "Philips Webcam",       /* Filled in later */
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_PWC,
+       .release =      video_device_release,
+       .fops =         &pwc_fops,
+       .minor =        -1,
+};
+
+/***************************************************************************/
+
+/* Okay, this is some magic that I worked out and the reasoning behind it...
+
+   The biggest problem with any USB device is of course: "what to do
+   when the user unplugs the device while it is in use by an application?"
+   We have several options:
+   1) Curse them with the 7 plagues when they do (requires divine intervention)
+   2) Tell them not to (won't work: they'll do it anyway)
+   3) Oops the kernel (this will have a negative effect on a user's uptime)
+   4) Do something sensible.
+
+   Of course, we go for option 4.
+
+   It happens that this device will be linked to two times, once from
+   usb_device and once from the video_device in their respective 'private'
+   pointers. This is done when the device is probed() and all initialization
+   succeeded. The pwc_device struct links back to both structures.
+
+   When a device is unplugged while in use it will be removed from the
+   list of known USB devices; I also de-register it as a V4L device, but
+   unfortunately I can't free the memory since the struct is still in use
+   by the file descriptor. This free-ing is then deferend until the first
+   opportunity. Crude, but it works.
+
+   A small 'advantage' is that if a user unplugs the cam and plugs it back
+   in, it should get assigned the same video device minor, but unfortunately
+   it's non-trivial to re-link the cam back to the video device... (that
+   would surely be magic! :))
+*/
+
+/***************************************************************************/
+/* Private functions */
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the area.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long kva, ret;
+
+       kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+       kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+       ret = __pa(kva);
+       return ret;
+}
+
+static void * rvmalloc(unsigned long size)
+{
+       void * mem;
+       unsigned long adr;
+
+       size=PAGE_ALIGN(size);
+       mem=vmalloc_32(size);
+       if (mem)
+       {
+               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+               adr=(unsigned long) mem;
+               while (size > 0)
+               {
+                       SetPageReserved(vmalloc_to_page((void *)adr));
+                       adr+=PAGE_SIZE;
+                       size-=PAGE_SIZE;
+               }
+       }
+       return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (mem)
+       {
+               adr=(unsigned long) mem;
+               while ((long) size > 0)
+               {
+                       ClearPageReserved(vmalloc_to_page((void *)adr));
+                       adr+=PAGE_SIZE;
+                       size-=PAGE_SIZE;
+               }
+               vfree(mem);
+       }
+}
+
+
+
+
+static int pwc_allocate_buffers(struct pwc_device *pdev)
+{
+       int i;
+       void *kbuf;
+
+       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+
+       if (pdev == NULL)
+               return -ENXIO;
+
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("allocate_buffers(): magic failed.\n");
+               return -ENXIO;
+       }
+#endif
+       /* Allocate Isochronous pipe buffers */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               if (pdev->sbuf[i].data == NULL) {
+                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+                       if (kbuf == NULL) {
+                               Err("Failed to allocate iso buffer %d.\n", i);
+                               return -ENOMEM;
+                       }
+                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+                       pdev->sbuf[i].data = kbuf;
+                       memset(kbuf, 0, ISO_BUFFER_SIZE);
+               }
+       }
+
+       /* Allocate frame buffer structure */
+       if (pdev->fbuf == NULL) {
+               kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+               if (kbuf == NULL) {
+                       Err("Failed to allocate frame buffer structure.\n");
+                       return -ENOMEM;
+               }
+               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+               pdev->fbuf = kbuf;
+               memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
+       }
+       /* create frame buffers, and make circular ring */
+       for (i = 0; i < default_fbufs; i++) {
+               if (pdev->fbuf[i].data == NULL) {
+                       kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
+                       if (kbuf == NULL) {
+                               Err("Failed to allocate frame buffer %d.\n", i);
+                               return -ENOMEM;
+                       }
+                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+                       pdev->fbuf[i].data = kbuf;
+                       memset(kbuf, 128, PWC_FRAME_SIZE);
+               }
+       }
+
+       /* Allocate decompressor table space */
+       kbuf = NULL;
+       switch (pdev->type)
+        {
+         case 675:
+         case 680:
+         case 690:
+         case 720:
+         case 730:
+         case 740:
+         case 750:
+#if 0
+           Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
+           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);       /* Timon & Kiara */
+           break;
+         case 645:
+         case 646:
+           /* TODO & FIXME */
+           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+           break;
+#endif
+       ;
+        }
+       pdev->decompress_data = kbuf;
+
+       /* Allocate image buffer; double buffer for mmap() */
+       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+       if (kbuf == NULL) {
+               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+               return -ENOMEM;
+       }
+       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+       pdev->image_data = kbuf;
+       for (i = 0; i < default_mbufs; i++)
+               pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
+       for (; i < MAX_IMAGES; i++)
+               pdev->image_ptr[i] = NULL;
+
+       kbuf = NULL;
+
+       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+       return 0;
+}
+
+static void pwc_free_buffers(struct pwc_device *pdev)
+{
+       int i;
+
+       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+
+       if (pdev == NULL)
+               return;
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("free_buffers(): magic failed.\n");
+               return;
+       }
+#endif
+
+       /* Release Iso-pipe buffers */
+       for (i = 0; i < MAX_ISO_BUFS; i++)
+               if (pdev->sbuf[i].data != NULL) {
+                       Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+                       kfree(pdev->sbuf[i].data);
+                       pdev->sbuf[i].data = NULL;
+               }
+
+       /* The same for frame buffers */
+       if (pdev->fbuf != NULL) {
+               for (i = 0; i < default_fbufs; i++) {
+                       if (pdev->fbuf[i].data != NULL) {
+                               Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+                               vfree(pdev->fbuf[i].data);
+                               pdev->fbuf[i].data = NULL;
+                       }
+               }
+               kfree(pdev->fbuf);
+               pdev->fbuf = NULL;
+       }
+
+       /* Intermediate decompression buffer & tables */
+       if (pdev->decompress_data != NULL) {
+               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+               kfree(pdev->decompress_data);
+               pdev->decompress_data = NULL;
+       }
+       pdev->decompressor = NULL;
+
+       /* Release image buffers */
+       if (pdev->image_data != NULL) {
+               Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
+               rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+       }
+       pdev->image_data = NULL;
+
+       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+}
+
+/* The frame & image buffer mess.
+
+   Yes, this is a mess. Well, it used to be simple, but alas...  In this
+   module, 3 buffers schemes are used to get the data from the USB bus to
+   the user program. The first scheme involves the ISO buffers (called thus
+   since they transport ISO data from the USB controller), and not really
+   interesting. Suffices to say the data from this buffer is quickly
+   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
+   frame buffer.
+
+   The frame buffer is the second scheme, and is the central element here.
+   It collects the data from a single frame from the camera (hence, the
+   name). Frames are delimited by the USB camera with a short USB packet,
+   so that's easy to detect. The frame buffers form a list that is filled
+   by the camera+USB controller and drained by the user process through
+   either read() or mmap().
+
+   The image buffer is the third scheme, in which frames are decompressed
+   and converted into planar format. For mmap() there is more than
+   one image buffer available.
+
+   The frame buffers provide the image buffering. In case the user process
+   is a bit slow, this introduces lag and some undesired side-effects.
+   The problem arises when the frame buffer is full. I used to drop the last
+   frame, which makes the data in the queue stale very quickly. But dropping
+   the frame at the head of the queue proved to be a litte bit more difficult.
+   I tried a circular linked scheme, but this introduced more problems than
+   it solved.
+
+   Because filling and draining are completely asynchronous processes, this
+   requires some fiddling with pointers and mutexes.
+
+   Eventually, I came up with a system with 2 lists: an 'empty' frame list
+   and a 'full' frame list:
+     * Initially, all frame buffers but one are on the 'empty' list; the one
+       remaining buffer is our initial fill frame.
+     * If a frame is needed for filling, we try to take it from the 'empty'
+       list, unless that list is empty, in which case we take the buffer at
+       the head of the 'full' list.
+     * When our fill buffer has been filled, it is appended to the 'full'
+       list.
+     * If a frame is needed by read() or mmap(), it is taken from the head of
+       the 'full' list, handled, and then appended to the 'empty' list. If no
+       buffer is present on the 'full' list, we wait.
+   The advantage is that the buffer that is currently being decompressed/
+   converted, is on neither list, and thus not in our way (any other scheme
+   I tried had the problem of old data lingering in the queue).
+
+   Whatever strategy you choose, it always remains a tradeoff: with more
+   frame buffers the chances of a missed frame are reduced. On the other
+   hand, on slower machines it introduces lag because the queue will
+   always be full.
+ */
+
+/**
+  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
+ */
+static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+{
+       int ret;
+       unsigned long flags;
+
+       ret = 0;
+       spin_lock_irqsave(&pdev->ptrlock, flags);
+       if (pdev->fill_frame != NULL) {
+               /* append to 'full' list */
+               if (pdev->full_frames == NULL) {
+                       pdev->full_frames = pdev->fill_frame;
+                       pdev->full_frames_tail = pdev->full_frames;
+               }
+               else {
+                       pdev->full_frames_tail->next = pdev->fill_frame;
+                       pdev->full_frames_tail = pdev->fill_frame;
+               }
+       }
+       if (pdev->empty_frames != NULL) {
+               /* We have empty frames available. That's easy */
+               pdev->fill_frame = pdev->empty_frames;
+               pdev->empty_frames = pdev->empty_frames->next;
+       }
+       else {
+               /* Hmm. Take it from the full list */
+#if PWC_DEBUG
+               /* sanity check */
+               if (pdev->full_frames == NULL) {
+                       Err("Neither empty or full frames available!\n");
+                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+                       return -EINVAL;
+               }
+#endif
+               pdev->fill_frame = pdev->full_frames;
+               pdev->full_frames = pdev->full_frames->next;
+               ret = 1;
+       }
+       pdev->fill_frame->next = NULL;
+#if PWC_DEBUG
+       Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
+       pdev->fill_frame->sequence = pdev->sequence++;
+#endif
+       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+       return ret;
+}
+
+
+/**
+  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
+
+  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
+ */
+static void pwc_reset_buffers(struct pwc_device *pdev)
+{
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdev->ptrlock, flags);
+       pdev->full_frames = NULL;
+       pdev->full_frames_tail = NULL;
+       for (i = 0; i < default_fbufs; i++) {
+               pdev->fbuf[i].filled = 0;
+               if (i > 0)
+                       pdev->fbuf[i].next = &pdev->fbuf[i - 1];
+               else
+                       pdev->fbuf->next = NULL;
+       }
+       pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
+       pdev->empty_frames_tail = pdev->fbuf;
+       pdev->read_frame = NULL;
+       pdev->fill_frame = pdev->empty_frames;
+       pdev->empty_frames = pdev->empty_frames->next;
+
+       pdev->image_read_pos = 0;
+       pdev->fill_image = 0;
+       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+}
+
+
+/**
+  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
+ */
+static int pwc_handle_frame(struct pwc_device *pdev)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdev->ptrlock, flags);
+       /* First grab our read_frame; this is removed from all lists, so
+          we can release the lock after this without problems */
+       if (pdev->read_frame != NULL) {
+               /* This can't theoretically happen */
+               Err("Huh? Read frame still in use?\n");
+       }
+       else {
+               if (pdev->full_frames == NULL) {
+                       Err("Woops. No frames ready.\n");
+               }
+               else {
+                       pdev->read_frame = pdev->full_frames;
+                       pdev->full_frames = pdev->full_frames->next;
+                       pdev->read_frame->next = NULL;
+               }
+
+               if (pdev->read_frame != NULL) {
+#if PWC_DEBUG
+                       Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
+#endif
+                       /* Decompression is a lenghty process, so it's outside of the lock.
+                          This gives the isoc_handler the opportunity to fill more frames
+                          in the mean time.
+                       */
+                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+                       ret = pwc_decompress(pdev);
+                       spin_lock_irqsave(&pdev->ptrlock, flags);
+
+                       /* We're done with read_buffer, tack it to the end of the empty buffer list */
+                       if (pdev->empty_frames == NULL) {
+                               pdev->empty_frames = pdev->read_frame;
+                               pdev->empty_frames_tail = pdev->empty_frames;
+                       }
+                       else {
+                               pdev->empty_frames_tail->next = pdev->read_frame;
+                               pdev->empty_frames_tail = pdev->read_frame;
+                       }
+                       pdev->read_frame = NULL;
+               }
+       }
+       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+       return ret;
+}
+
+/**
+  \brief Advance pointers of image buffer (after each user request)
+*/
+static inline void pwc_next_image(struct pwc_device *pdev)
+{
+       pdev->image_used[pdev->fill_image] = 0;
+       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+}
+
+
+/* This gets called for the Isochronous pipe (video). This is done in
+ * interrupt time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
+{
+       struct pwc_device *pdev;
+       int i, fst, flen;
+       int awake;
+       struct pwc_frame_buf *fbuf;
+       unsigned char *fillptr = NULL, *iso_buf = NULL;
+
+       awake = 0;
+       pdev = (struct pwc_device *)urb->context;
+       if (pdev == NULL) {
+               Err("isoc_handler() called with NULL device?!\n");
+               return;
+       }
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("isoc_handler() called with bad magic!\n");
+               return;
+       }
+#endif
+       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+               Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+               return;
+       }
+       if (urb->status != -EINPROGRESS && urb->status != 0) {
+               const char *errmsg;
+
+               errmsg = "Unknown";
+               switch(urb->status) {
+                       case -ENOSR:            errmsg = "Buffer error (overrun)"; break;
+                       case -EPIPE:            errmsg = "Stalled (device not responding)"; break;
+                       case -EOVERFLOW:        errmsg = "Babble (bad cable?)"; break;
+                       case -EPROTO:           errmsg = "Bit-stuff error (bad cable?)"; break;
+                       case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
+                       case -ETIMEDOUT:        errmsg = "NAK (device does not respond)"; break;
+               }
+               Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+               /* Give up after a number of contiguous errors on the USB bus.
+                  Appearantly something is wrong so we simulate an unplug event.
+                */
+               if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
+               {
+                       Info("Too many ISOC errors, bailing out.\n");
+                       pdev->error_status = EIO;
+                       awake = 1;
+                       wake_up_interruptible(&pdev->frameq);
+               }
+               goto handler_end; // ugly, but practical
+       }
+
+       fbuf = pdev->fill_frame;
+       if (fbuf == NULL) {
+               Err("pwc_isoc_handler without valid fill frame.\n");
+               awake = 1;
+               goto handler_end;
+       }
+       else {
+               fillptr = fbuf->data + fbuf->filled;
+       }
+
+       /* Reset ISOC error counter. We did get here, after all. */
+       pdev->visoc_errors = 0;
+
+       /* vsync: 0 = don't copy data
+                 1 = sync-hunt
+                 2 = synched
+        */
+       /* Compact data */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               fst  = urb->iso_frame_desc[i].status;
+               flen = urb->iso_frame_desc[i].actual_length;
+               iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               if (fst == 0) {
+                       if (flen > 0) { /* if valid data... */
+                               if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
+                                       pdev->vsync = 2;
+
+                                       /* ...copy data to frame buffer, if possible */
+                                       if (flen + fbuf->filled > pdev->frame_total_size) {
+                                               Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+                                               pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
+                                               pdev->vframes_error++;
+                                       }
+                                       else {
+                                               memmove(fillptr, iso_buf, flen);
+                                               fillptr += flen;
+                                       }
+                               }
+                               fbuf->filled += flen;
+                       } /* ..flen > 0 */
+
+                       if (flen < pdev->vlast_packet_size) {
+                               /* Shorter packet... We probably have the end of an image-frame;
+                                  wake up read() process and let select()/poll() do something.
+                                  Decompression is done in user time over there.
+                                */
+                               if (pdev->vsync == 2) {
+                                       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+                                          frames on the USB wire after an exposure change. This conditition is
+                                          however detected  in the cam and a bit is set in the header.
+                                        */
+                                       if (pdev->type == 730) {
+                                               unsigned char *ptr = (unsigned char *)fbuf->data;
+
+                                               if (ptr[1] == 1 && ptr[0] & 0x10) {
+#if PWC_DEBUG
+                                                       Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
+#endif
+                                                       pdev->drop_frames += 2;
+                                                       pdev->vframes_error++;
+                                               }
+                                               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                                                       if (ptr[0] & 0x01)
+                                                               Info("Snapshot button pressed.\n");
+                                                       else
+                                                               Info("Snapshot button released.\n");
+                                               }
+                                               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+                                                       if (ptr[0] & 0x02)
+                                                               Info("Image is mirrored.\n");
+                                                       else
+                                                               Info("Image is normal.\n");
+                                               }
+                                               pdev->vmirror = ptr[0] & 0x03;
+                                               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+                                                  after a short frame; this condition is filtered out specifically. A 4 byte
+                                                  frame doesn't make sense anyway.
+                                                  So we get either this sequence:
+                                                       drop_bit set -> 4 byte frame -> short frame -> good frame
+                                                  Or this one:
+                                                       drop_bit set -> short frame -> good frame
+                                                  So we drop either 3 or 2 frames in all!
+                                                */
+                                               if (fbuf->filled == 4)
+                                                       pdev->drop_frames++;
+                                       }
+
+                                       /* In case we were instructed to drop the frame, do so silently.
+                                          The buffer pointers are not updated either (but the counters are reset below).
+                                        */
+                                       if (pdev->drop_frames > 0)
+                                               pdev->drop_frames--;
+                                       else {
+                                               /* Check for underflow first */
+                                               if (fbuf->filled < pdev->frame_total_size) {
+                                                       Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
+                                                       pdev->vframes_error++;
+                                               }
+                                               else {
+                                                       /* Send only once per EOF */
+                                                       awake = 1; /* delay wake_ups */
+
+                                                       /* Find our next frame to fill. This will always succeed, since we
+                                                        * nick a frame from either empty or full list, but if we had to
+                                                        * take it from the full list, it means a frame got dropped.
+                                                        */
+                                                       if (pwc_next_fill_frame(pdev)) {
+                                                               pdev->vframes_dumped++;
+                                                               if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
+                                                                       if (pdev->vframes_dumped < 20)
+                                                                               Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
+                                                                       if (pdev->vframes_dumped == 20)
+                                                                               Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
+                                                               }
+                                                       }
+                                                       fbuf = pdev->fill_frame;
+                                               }
+                                       } /* !drop_frames */
+                                       pdev->vframe_count++;
+                               }
+                               fbuf->filled = 0;
+                               fillptr = fbuf->data;
+                               pdev->vsync = 1;
+                       } /* .. flen < last_packet_size */
+                       pdev->vlast_packet_size = flen;
+               } /* ..status == 0 */
+#if PWC_DEBUG
+               /* This is normally not interesting to the user, unless you are really debugging something */
+               else {
+                       static int iso_error = 0;
+                       iso_error++;
+                       if (iso_error < 20)
+                               Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+               }
+#endif
+       }
+
+handler_end:
+       if (awake)
+               wake_up_interruptible(&pdev->frameq);
+
+       urb->dev = pdev->udev;
+       i = usb_submit_urb(urb, GFP_ATOMIC);
+       if (i != 0)
+               Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+}
+
+
+static int pwc_isoc_init(struct pwc_device *pdev)
+{
+       struct usb_device *udev;
+       struct urb *urb;
+       int i, j, ret;
+
+       struct usb_interface *intf;
+       struct usb_host_interface *idesc = NULL;
+
+       if (pdev == NULL)
+               return -EFAULT;
+       if (pdev->iso_init)
+               return 0;
+       pdev->vsync = 0;
+       udev = pdev->udev;
+
+       /* Get the current alternate interface, adjust packet size */
+       if (!udev->actconfig)
+               return -EFAULT;
+
+       intf = usb_ifnum_to_if(udev, 0);
+       if (intf)
+               idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
+
+       if (!idesc)
+               return -EFAULT;
+
+       /* Search video endpoint */
+       pdev->vmax_packet_size = -1;
+       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+               if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
+                       pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
+                       break;
+               }
+
+       if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
+               Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+               return -ENFILE; /* Odd error, that should be noticeable */
+       }
+
+       /* Set alternate interface */
+       ret = 0;
+       Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+       ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
+               if (urb == NULL) {
+                       Err("Failed to allocate urb %d\n", i);
+                       ret = -ENOMEM;
+                       break;
+               }
+               pdev->sbuf[i].urb = urb;
+               Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+       }
+       if (ret) {
+               /* De-allocate in reverse order */
+               while (i >= 0) {
+                       if (pdev->sbuf[i].urb != NULL)
+                               usb_free_urb(pdev->sbuf[i].urb);
+                       pdev->sbuf[i].urb = NULL;
+                       i--;
+               }
+               return ret;
+       }
+
+       /* init URB structure */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               urb = pdev->sbuf[i].urb;
+
+               urb->interval = 1; // devik
+               urb->dev = udev;
+               urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = pdev->sbuf[i].data;
+               urb->transfer_buffer_length = ISO_BUFFER_SIZE;
+               urb->complete = pwc_isoc_handler;
+               urb->context = pdev;
+               urb->start_frame = 0;
+               urb->number_of_packets = ISO_FRAMES_PER_DESC;
+               for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
+                       urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
+                       urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
+               }
+       }
+
+       /* link */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
+               if (ret)
+                       Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+               else
+                       Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+       }
+
+       /* All is done... */
+       pdev->iso_init = 1;
+       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+       return 0;
+}
+
+static void pwc_isoc_cleanup(struct pwc_device *pdev)
+{
+       int i;
+
+       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+       if (pdev == NULL)
+               return;
+
+       /* Unlinking ISOC buffers one by one */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               struct urb *urb;
+
+               urb = pdev->sbuf[i].urb;
+               if (urb != 0) {
+                       if (pdev->iso_init) {
+                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+                               usb_kill_urb(urb);
+                       }
+                       Trace(TRACE_MEMORY, "Freeing URB\n");
+                       usb_free_urb(urb);
+                       pdev->sbuf[i].urb = NULL;
+               }
+       }
+
+       /* Stop camera, but only if we are sure the camera is still there (unplug
+          is signalled by EPIPE)
+        */
+       if (pdev->error_status && pdev->error_status != EPIPE) {
+               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+               usb_set_interface(pdev->udev, 0, 0);
+       }
+
+       pdev->iso_init = 0;
+       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+}
+
+int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
+{
+       int ret, start;
+
+       /* Stop isoc stuff */
+       pwc_isoc_cleanup(pdev);
+       /* Reset parameters */
+       pwc_reset_buffers(pdev);
+       /* Try to set video mode... */
+       start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
+       if (ret) {
+               Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+               /* That failed... restore old mode (we know that worked) */
+               start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+               if (start) {
+                       Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+               }
+       }
+       if (start == 0)
+       {
+               if (pwc_isoc_init(pdev) < 0)
+               {
+                       Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+                       ret = -EAGAIN; /* let's try again, who knows if it works a second time */
+               }
+       }
+       pdev->drop_frames++; /* try to avoid garbage during switch */
+       return ret; /* Return original error code */
+}
+
+
+/***************************************************************************/
+/* Video4Linux functions */
+
+static int pwc_video_open(struct inode *inode, struct file *file)
+{
+       int i;
+       struct video_device *vdev = video_devdata(file);
+       struct pwc_device *pdev;
+
+       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+
+       pdev = (struct pwc_device *)vdev->priv;
+       if (pdev == NULL)
+               BUG();
+       if (pdev->vopen)
+               return -EBUSY;
+
+       down(&pdev->modlock);
+       if (!pdev->usb_init) {
+               Trace(TRACE_OPEN, "Doing first time initialization.\n");
+               pdev->usb_init = 1;
+
+               if (pwc_trace & TRACE_OPEN)
+               {
+                       /* Query sensor type */
+                       const char *sensor_type = NULL;
+                       int ret;
+
+                       ret = pwc_get_cmos_sensor(pdev, &i);
+                       if (ret >= 0)
+                       {
+                               switch(i) {
+                               case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
+                               case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
+                               case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
+                               case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
+                               case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
+                               case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
+                               case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
+                               case 0x40:  sensor_type = "UPA 1021 sensor"; break;
+                               case 0x100: sensor_type = "VGA sensor"; break;
+                               case 0x101: sensor_type = "PAL MR sensor"; break;
+                               default:    sensor_type = "unknown type of sensor"; break;
+                               }
+                       }
+                       if (sensor_type != NULL)
+                               Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+               }
+       }
+
+       /* Turn on camera */
+       if (power_save) {
+               i = pwc_camera_power(pdev, 1);
+               if (i < 0)
+                       Info("Failed to restore power to the camera! (%d)\n", i);
+       }
+       /* Set LED on/off time */
+       if (pwc_set_leds(pdev, led_on, led_off) < 0)
+               Info("Failed to set LED on/off time.\n");
+
+       pwc_construct(pdev); /* set min/max sizes correct */
+
+       /* So far, so good. Allocate memory. */
+       i = pwc_allocate_buffers(pdev);
+       if (i < 0) {
+               Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+               up(&pdev->modlock);
+               return i;
+       }
+
+       /* Reset buffers & parameters */
+       pwc_reset_buffers(pdev);
+       for (i = 0; i < default_mbufs; i++)
+               pdev->image_used[i] = 0;
+       pdev->vframe_count = 0;
+       pdev->vframes_dumped = 0;
+       pdev->vframes_error = 0;
+       pdev->visoc_errors = 0;
+       pdev->error_status = 0;
+#if PWC_DEBUG
+       pdev->sequence = 0;
+#endif
+       pwc_construct(pdev); /* set min/max sizes correct */
+
+       /* Set some defaults */
+       pdev->vsnapshot = 0;
+
+       /* Start iso pipe for video; first try the last used video size
+          (or the default one); if that fails try QCIF/10 or QSIF/10;
+          it that fails too, give up.
+        */
+       i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
+       if (i)  {
+               Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
+               if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
+                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+               else
+                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+       }
+       if (i) {
+               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+               up(&pdev->modlock);
+               return i;
+       }
+
+       i = pwc_isoc_init(pdev);
+       if (i) {
+               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+               up(&pdev->modlock);
+               return i;
+       }
+
+       pdev->vopen++;
+       file->private_data = vdev;
+       up(&pdev->modlock);
+       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+       return 0;
+}
+
+/* Note that all cleanup is done in the reverse order as in _open */
+static int pwc_video_close(struct inode *inode, struct file *file)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       int i;
+
+       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+
+       pdev = (struct pwc_device *)vdev->priv;
+       if (pdev->vopen == 0)
+               Info("video_close() called on closed device?\n");
+
+       /* Dump statistics, but only if a reasonable amount of frames were
+          processed (to prevent endless log-entries in case of snap-shot
+          programs)
+        */
+       if (pdev->vframe_count > 20)
+               Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+
+       switch (pdev->type)
+        {
+         case 675:
+         case 680:
+         case 690:
+         case 720:
+         case 730:
+         case 740:
+         case 750:
+/*         pwc_dec23_exit();   *//* Timon & Kiara */
+           break;
+         case 645:
+         case 646:
+/*         pwc_dec1_exit(); */
+           break;
+        }
+
+       pwc_isoc_cleanup(pdev);
+       pwc_free_buffers(pdev);
+
+       /* Turn off LEDS and power down camera, but only when not unplugged */
+       if (pdev->error_status != EPIPE) {
+               /* Turn LEDs off */
+               if (pwc_set_leds(pdev, 0, 0) < 0)
+                       Info("Failed to set LED on/off time.\n");
+               if (power_save) {
+                       i = pwc_camera_power(pdev, 0);
+                       if (i < 0)
+                               Err("Failed to power down camera (%d)\n", i);
+               }
+       }
+       pdev->vopen = 0;
+       Trace(TRACE_OPEN, "<< video_close()\n");
+       return 0;
+}
+
+/*
+ *     FIXME: what about two parallel reads ????
+ *      ANSWER: Not supported. You can't open the device more than once,
+               despite what the V4L1 interface says. First, I don't see
+               the need, second there's no mechanism of alerting the
+               2nd/3rd/... process of events like changing image size.
+               And I don't see the point of blocking that for the
+               2nd/3rd/... process.
+               In multi-threaded environments reading parallel from any
+               device is tricky anyhow.
+ */
+
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
+                         size_t count, loff_t *ppos)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       int noblock = file->f_flags & O_NONBLOCK;
+       DECLARE_WAITQUEUE(wait, current);
+       int bytes_to_read;
+
+       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+       if (pdev->error_status)
+               return -pdev->error_status; /* Something happened, report what. */
+
+       /* In case we're doing partial reads, we don't have to wait for a frame */
+       if (pdev->image_read_pos == 0) {
+               /* Do wait queueing according to the (doc)book */
+               add_wait_queue(&pdev->frameq, &wait);
+               while (pdev->full_frames == NULL) {
+                       /* Check for unplugged/etc. here */
+                       if (pdev->error_status) {
+                               remove_wait_queue(&pdev->frameq, &wait);
+                               set_current_state(TASK_RUNNING);
+                               return -pdev->error_status ;
+                       }
+                       if (noblock) {
+                               remove_wait_queue(&pdev->frameq, &wait);
+                               set_current_state(TASK_RUNNING);
+                               return -EWOULDBLOCK;
+                       }
+                       if (signal_pending(current)) {
+                               remove_wait_queue(&pdev->frameq, &wait);
+                               set_current_state(TASK_RUNNING);
+                               return -ERESTARTSYS;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+               remove_wait_queue(&pdev->frameq, &wait);
+               set_current_state(TASK_RUNNING);
+
+               /* Decompress and release frame */
+               if (pwc_handle_frame(pdev))
+                       return -EFAULT;
+       }
+
+       Trace(TRACE_READ, "Copying data to user space.\n");
+       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+               bytes_to_read = pdev->frame_size;
+       else
+               bytes_to_read = pdev->view.size;
+
+       /* copy bytes to user space; we allow for partial reads */
+       if (count + pdev->image_read_pos > bytes_to_read)
+               count = bytes_to_read - pdev->image_read_pos;
+       if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+               return -EFAULT;
+       pdev->image_read_pos += count;
+       if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
+               pdev->image_read_pos = 0;
+               pwc_next_image(pdev);
+       }
+       return count;
+}
+
+static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+       poll_wait(file, &pdev->frameq, wait);
+       if (pdev->error_status)
+               return POLLERR;
+       if (pdev->full_frames != NULL) /* we have frames waiting */
+               return (POLLIN | POLLRDNORM);
+
+       return 0;
+}
+
+static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+       switch (cmd) {
+               /* Query cabapilities */
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *caps = arg;
+
+                       strcpy(caps->name, vdev->name);
+                       caps->type = VID_TYPE_CAPTURE;
+                       caps->channels = 1;
+                       caps->audios = 1;
+                       caps->minwidth  = pdev->view_min.x;
+                       caps->minheight = pdev->view_min.y;
+                       caps->maxwidth  = pdev->view_max.x;
+                       caps->maxheight = pdev->view_max.y;
+                       break;
+               }
+
+               /* Channel functions (simulate 1 channel) */
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy(v->name, "Webcam");
+                       return 0;
+               }
+
+               case VIDIOCSCHAN:
+               {
+                       /* The spec says the argument is an integer, but
+                          the bttv driver uses a video_channel arg, which
+                          makes sense becasue it also has the norm flag.
+                        */
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+
+
+               /* Picture functions; contrast etc. */
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *p = arg;
+                       int val;
+
+                       val = pwc_get_brightness(pdev);
+                       if (val >= 0)
+                               p->brightness = val;
+                       else
+                               p->brightness = 0xffff;
+                       val = pwc_get_contrast(pdev);
+                       if (val >= 0)
+                               p->contrast = val;
+                       else
+                               p->contrast = 0xffff;
+                       /* Gamma, Whiteness, what's the difference? :) */
+                       val = pwc_get_gamma(pdev);
+                       if (val >= 0)
+                               p->whiteness = val;
+                       else
+                               p->whiteness = 0xffff;
+                       val = pwc_get_saturation(pdev);
+                       if (val >= 0)
+                               p->colour = val;
+                       else
+                               p->colour = 0xffff;
+                       p->depth = 24;
+                       p->palette = pdev->vpalette;
+                       p->hue = 0xFFFF; /* N/A */
+                       break;
+               }
+
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *p = arg;
+                       /*
+                        *      FIXME:  Suppose we are mid read
+                               ANSWER: No problem: the firmware of the camera
+                                       can handle brightness/contrast/etc
+                                       changes at _any_ time, and the palette
+                                       is used exactly once in the uncompress
+                                       routine.
+                        */
+                       pwc_set_brightness(pdev, p->brightness);
+                       pwc_set_contrast(pdev, p->contrast);
+                       pwc_set_gamma(pdev, p->whiteness);
+                       pwc_set_saturation(pdev, p->colour);
+                       if (p->palette && p->palette != pdev->vpalette) {
+                               switch (p->palette) {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               pdev->vpalette = p->palette;
+                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+                       break;
+               }
+
+               /* Window/size parameters */
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = pdev->view.x;
+                       vw->height = pdev->view.y;
+                       vw->chromakey = 0;
+                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+                       break;
+               }
+
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+                       int fps, snapshot, ret;
+
+                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+                       if (fps == 0)
+                               fps = pdev->vframes;
+                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+                               return 0;
+                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+
+               /* We don't have overlay support (yet) */
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb,0,sizeof(*vb));
+                       break;
+               }
+
+               /* mmap() functions */
+               case VIDIOCGMBUF:
+               {
+                       /* Tell the user program how much memory is needed for a mmap() */
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset(vm, 0, sizeof(*vm));
+                       vm->size = default_mbufs * pdev->len_per_image;
+                       vm->frames = default_mbufs; /* double buffering should be enough for most applications */
+                       for (i = 0; i < default_mbufs; i++)
+                               vm->offsets[i] = i * pdev->len_per_image;
+                       break;
+               }
+
+               case VIDIOCMCAPTURE:
+               {
+                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+                       struct video_mmap *vm = arg;
+
+                       Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+                       if (vm->frame < 0 || vm->frame >= default_mbufs)
+                               return -EINVAL;
+
+                       /* xawtv is nasty. It probes the available palettes
+                          by setting a very small image size and trying
+                          various palettes... The driver doesn't support
+                          such small images, so I'm working around it.
+                        */
+                       if (vm->format)
+                       {
+                               switch (vm->format)
+                               {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+
+                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+                               int ret;
+
+                               Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                               if (ret)
+                                       return ret;
+                       } /* ... size mismatch */
+
+                       /* FIXME: should we lock here? */
+                       if (pdev->image_used[vm->frame])
+                               return -EBUSY;  /* buffer wasn't available. Bummer */
+                       pdev->image_used[vm->frame] = 1;
+
+                       /* Okay, we're done here. In the SYNC call we wait until a
+                          frame comes available, then expand image into the given
+                          buffer.
+                          In contrast to the CPiA cam the Philips cams deliver a
+                          constant stream, almost like a grabber card. Also,
+                          we have separate buffers for the rawdata and the image,
+                          meaning we can nearly always expand into the requested buffer.
+                        */
+                       Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
+                       break;
+               }
+
+               case VIDIOCSYNC:
+               {
+                       /* The doc says: "Whenever a buffer is used it should
+                          call VIDIOCSYNC to free this frame up and continue."
+
+                          The only odd thing about this whole procedure is
+                          that MCAPTURE flags the buffer as "in use", and
+                          SYNC immediately unmarks it, while it isn't
+                          after SYNC that you know that the buffer actually
+                          got filled! So you better not start a CAPTURE in
+                          the same frame immediately (use double buffering).
+                          This is not a problem for this cam, since it has
+                          extra intermediate buffers, but a hardware
+                          grabber card will then overwrite the buffer
+                          you're working on.
+                        */
+                       int *mbuf = arg;
+                       int ret;
+
+                       Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
+
+                       /* bounds check */
+                       if (*mbuf < 0 || *mbuf >= default_mbufs)
+                               return -EINVAL;
+                       /* check if this buffer was requested anyway */
+                       if (pdev->image_used[*mbuf] == 0)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+
+                               if (signal_pending(current)) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -ERESTARTSYS;
+                               }
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+
+                       /* The frame is ready. Expand in the image buffer
+                          requested by the user. I don't care if you
+                          mmap() 5 buffers and request data in this order:
+                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+                          Grabber hardware may not be so forgiving.
+                        */
+                       Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
+                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+                       /* Decompress, etc */
+                       ret = pwc_handle_frame(pdev);
+                       pdev->image_used[*mbuf] = 0;
+                       if (ret)
+                               return -EFAULT;
+                       break;
+               }
+
+               case VIDIOCGAUDIO:
+               {
+                       struct video_audio *v = arg;
+
+                       strcpy(v->name, "Microphone");
+                       v->audio = -1; /* unknown audio minor */
+                       v->flags = 0;
+                       v->mode = VIDEO_SOUND_MONO;
+                       v->volume = 0;
+                       v->bass = 0;
+                       v->treble = 0;
+                       v->balance = 0x8000;
+                       v->step = 1;
+                       break;
+               }
+
+               case VIDIOCSAUDIO:
+               {
+                       /* Dummy: nothing can be set */
+                       break;
+               }
+
+               case VIDIOCGUNIT:
+               {
+                       struct video_unit *vu = arg;
+
+                       vu->video = pdev->vdev->minor & 0x3F;
+                       vu->audio = -1; /* not known yet */
+                       vu->vbi = -1;
+                       vu->radio = -1;
+                       vu->teletext = -1;
+                       break;
+               }
+               default:
+                       return pwc_ioctl(pdev, cmd, arg);
+       } /* ..switch */
+       return 0;
+}
+
+static int pwc_video_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+}
+
+
+static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+       pdev = vdev->priv;
+
+       vma->vm_flags |= VM_IO;
+
+       pos = (unsigned long)pdev->image_data;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+/***************************************************************************/
+/* USB functions */
+
+/* This function gets called when a new device is plugged in or the usb core
+ * is loaded.
+ */
+
+static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct pwc_device *pdev = NULL;
+       int vendor_id, product_id, type_id;
+       int i, hint;
+       int features = 0;
+       int video_nr = -1; /* default: use next available device */
+       char serial_number[30], *name;
+
+       /* Check if we can handle this device */
+       Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct),
+               intf->altsetting->desc.bInterfaceNumber);
+
+       /* the interfaces are probed one by one. We are only interested in the
+          video interface (0) now.
+          Interface 1 is the Audio Control, and interface 2 Audio itself.
+        */
+       if (intf->altsetting->desc.bInterfaceNumber > 0)
+               return -ENODEV;
+
+       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+       product_id = le16_to_cpu(udev->descriptor.idProduct);
+
+       if (vendor_id == 0x0471) {
+               switch (product_id) {
+               case 0x0302:
+                       Info("Philips PCA645VC USB webcam detected.\n");
+                       name = "Philips 645 webcam";
+                       type_id = 645;
+                       break;
+               case 0x0303:
+                       Info("Philips PCA646VC USB webcam detected.\n");
+                       name = "Philips 646 webcam";
+                       type_id = 646;
+                       break;
+               case 0x0304:
+                       Info("Askey VC010 type 2 USB webcam detected.\n");
+                       name = "Askey VC010 webcam";
+                       type_id = 646;
+                       break;
+               case 0x0307:
+                       Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+                       name = "Philips 675 webcam";
+                       type_id = 675;
+                       break;
+               case 0x0308:
+                       Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+                       name = "Philips 680 webcam";
+                       type_id = 680;
+                       break;
+               case 0x030C:
+                       Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+                       name = "Philips 690 webcam";
+                       type_id = 690;
+                       break;
+               case 0x0310:
+                       Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+                       name = "Philips 730 webcam";
+                       type_id = 730;
+                       break;
+               case 0x0311:
+                       Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+                       name = "Philips 740 webcam";
+                       type_id = 740;
+                       break;
+               case 0x0312:
+                       Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+                       name = "Philips 750 webcam";
+                       type_id = 750;
+                       break;
+               case 0x0313:
+                       Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+                       name = "Philips 720K/40 webcam";
+                       type_id = 720;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x069A) {
+               switch(product_id) {
+               case 0x0001:
+                       Info("Askey VC010 type 1 USB webcam detected.\n");
+                       name = "Askey VC010 webcam";
+                       type_id = 645;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x046d) {
+               switch(product_id) {
+               case 0x08b0:
+                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+                       name = "Logitech QuickCam Pro 3000";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b1:
+                       Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+                       name = "Logitech QuickCam Notebook Pro";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b2:
+                       Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+                       name = "Logitech QuickCam Pro 4000";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b3:
+                       Info("Logitech QuickCam Zoom USB webcam detected.\n");
+                       name = "Logitech QuickCam Zoom";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08B4:
+                       Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+                       name = "Logitech QuickCam Zoom";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b5:
+                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+                       name = "Logitech QuickCam Orbit";
+                       type_id = 740; /* CCD sensor */
+                       features |= FEATURE_MOTOR_PANTILT;
+                       break;
+               case 0x08b6:
+               case 0x08b7:
+               case 0x08b8:
+                       Info("Logitech QuickCam detected (reserved ID).\n");
+                       name = "Logitech QuickCam (res.)";
+                       type_id = 730; /* Assuming CMOS */
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x055d) {
+               /* I don't know the difference between the C10 and the C30;
+                  I suppose the difference is the sensor, but both cameras
+                  work equally well with a type_id of 675
+                */
+               switch(product_id) {
+               case 0x9000:
+                       Info("Samsung MPC-C10 USB webcam detected.\n");
+                       name = "Samsung MPC-C10";
+                       type_id = 675;
+                       break;
+               case 0x9001:
+                       Info("Samsung MPC-C30 USB webcam detected.\n");
+                       name = "Samsung MPC-C30";
+                       type_id = 675;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x041e) {
+               switch(product_id) {
+               case 0x400c:
+                       Info("Creative Labs Webcam 5 detected.\n");
+                       name = "Creative Labs Webcam 5";
+                       type_id = 730;
+                       break;
+               case 0x4011:
+                       Info("Creative Labs Webcam Pro Ex detected.\n");
+                       name = "Creative Labs Webcam Pro Ex";
+                       type_id = 740;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x04cc) {
+               switch(product_id) {
+               case 0x8116:
+                       Info("Sotec Afina Eye USB webcam detected.\n");
+                       name = "Sotec Afina Eye";
+                       type_id = 730;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x06be) {
+               switch(product_id) {
+               case 0x8116:
+                       /* This is essentially the same cam as the Sotec Afina Eye */
+                       Info("AME Co. Afina Eye USB webcam detected.\n");
+                       name = "AME Co. Afina Eye";
+                       type_id = 750;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+
+       }
+       else if (vendor_id == 0x0d81) {
+               switch(product_id) {
+               case 0x1900:
+                       Info("Visionite VCS-UC300 USB webcam detected.\n");
+                       name = "Visionite VCS-UC300";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x1910:
+                       Info("Visionite VCS-UM100 USB webcam detected.\n");
+                       name = "Visionite VCS-UM100";
+                       type_id = 730; /* CMOS sensor */
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else
+               return -ENODEV; /* Not any of the know types; but the list keeps growing. */
+
+       memset(serial_number, 0, 30);
+       usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
+       Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+
+       if (udev->descriptor.bNumConfigurations > 1)
+               Info("Warning: more than 1 configuration available.\n");
+
+       /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
+       pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
+       if (pdev == NULL) {
+               Err("Oops, could not allocate memory for pwc_device.\n");
+               return -ENOMEM;
+       }
+       pdev->type = type_id;
+       pdev->vsize = default_size;
+       pdev->vframes = default_fps;
+       strcpy(pdev->serial, serial_number);
+       pdev->features = features;
+       if (vendor_id == 0x046D && product_id == 0x08B5)
+       {
+               /* Logitech QuickCam Orbit
+                  The ranges have been determined experimentally; they may differ from cam to cam.
+                  Also, the exact ranges left-right and up-down are different for my cam
+                 */
+               pdev->angle_range.pan_min  = -7000;
+               pdev->angle_range.pan_max  =  7000;
+               pdev->angle_range.tilt_min = -3000;
+               pdev->angle_range.tilt_max =  2500;
+       }
+
+       init_MUTEX(&pdev->modlock);
+       spin_lock_init(&pdev->ptrlock);
+
+       pdev->udev = udev;
+       init_waitqueue_head(&pdev->frameq);
+       pdev->vcompression = pwc_preferred_compression;
+
+       /* Allocate video_device structure */
+       pdev->vdev = video_device_alloc();
+       if (pdev->vdev == 0)
+       {
+               Err("Err, cannot allocate video_device struture. Failing probe.");
+               kfree(pdev);
+               return -ENOMEM;
+       }
+       memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+       strcpy(pdev->vdev->name, name);
+       pdev->vdev->owner = THIS_MODULE;
+       video_set_drvdata(pdev->vdev, pdev);
+
+       pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
+       Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+
+       /* Now search device_hint[] table for a match, so we can hint a node number. */
+       for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
+               if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
+                    (device_hint[hint].pdev == NULL)) {
+                       /* so far, so good... try serial number */
+                       if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
+                               /* match! */
+                               video_nr = device_hint[hint].device_node;
+                               Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+                               break;
+                       }
+               }
+       }
+
+       pdev->vdev->release = video_device_release;
+       i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (i < 0) {
+               Err("Failed to register as video device (%d).\n", i);
+               video_device_release(pdev->vdev); /* Drip... drip... drip... */
+               kfree(pdev); /* Oops, no memory leaks please */
+               return -EIO;
+       }
+       else {
+               Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+       }
+
+       /* occupy slot */
+       if (hint < MAX_DEV_HINTS)
+               device_hint[hint].pdev = pdev;
+
+       Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+       usb_set_intfdata (intf, pdev);
+       return 0;
+}
+
+/* The user janked out the cable... */
+static void usb_pwc_disconnect(struct usb_interface *intf)
+{
+       struct pwc_device *pdev;
+       int hint;
+
+       lock_kernel();
+       pdev = usb_get_intfdata (intf);
+       usb_set_intfdata (intf, NULL);
+       if (pdev == NULL) {
+               Err("pwc_disconnect() Called without private pointer.\n");
+               goto disconnect_out;
+       }
+       if (pdev->udev == NULL) {
+               Err("pwc_disconnect() already called for %p\n", pdev);
+               goto disconnect_out;
+       }
+       if (pdev->udev != interface_to_usbdev(intf)) {
+               Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+               goto disconnect_out;
+       }
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+               goto disconnect_out;
+       }
+#endif
+
+       /* We got unplugged; this is signalled by an EPIPE error code */
+       if (pdev->vopen) {
+               Info("Disconnected while webcam is in use!\n");
+               pdev->error_status = EPIPE;
+       }
+
+       /* Alert waiting processes */
+       wake_up_interruptible(&pdev->frameq);
+       /* Wait until device is closed */
+       while (pdev->vopen)
+               schedule();
+       /* Device is now closed, so we can safely unregister it */
+       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+       video_unregister_device(pdev->vdev);
+
+       /* Free memory (don't set pdev to 0 just yet) */
+       kfree(pdev);
+
+disconnect_out:
+       /* search device_hint[] table if we occupy a slot, by any chance */
+       for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+               if (device_hint[hint].pdev == pdev)
+                       device_hint[hint].pdev = NULL;
+
+       unlock_kernel();
+}
+
+
+/* *grunt* We have to do atoi ourselves :-( */
+static int pwc_atoi(const char *s)
+{
+       int k = 0;
+
+       k = 0;
+       while (*s != '\0' && *s >= '0' && *s <= '9') {
+               k = 10 * k + (*s - '0');
+               s++;
+       }
+       return k;
+}
+
+
+/*
+ * Initialization code & module stuff
+ */
+
+static char size[10];
+static int fps = 0;
+static int fbufs = 0;
+static int mbufs = 0;
+static int trace = -1;
+static int compression = -1;
+static int leds[2] = { -1, -1 };
+static char *dev_hint[MAX_DEV_HINTS] = { };
+
+module_param_string(size, size, sizeof(size), 0);
+MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
+module_param(fps, int, 0000);
+MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
+module_param(fbufs, int, 0000);
+MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
+module_param(mbufs, int, 0000);
+MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
+module_param(trace, int, 0000);
+MODULE_PARM_DESC(trace, "For debugging purposes");
+module_param(power_save, bool, 0000);
+MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
+module_param(compression, int, 0000);
+MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
+module_param_array(leds, int, NULL, 0000);
+MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
+module_param_array(dev_hint, charp, NULL, 0000);
+MODULE_PARM_DESC(dev_hint, "Device node hints");
+
+MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
+MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
+MODULE_LICENSE("GPL");
+
+static int __init usb_pwc_init(void)
+{
+       int i, sz;
+       char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
+
+       Info("Philips webcam module version " PWC_VERSION " loaded.\n");
+       Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+       Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+       Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+
+       if (fps) {
+               if (fps < 4 || fps > 30) {
+                       Err("Framerate out of bounds (4-30).\n");
+                       return -EINVAL;
+               }
+               default_fps = fps;
+               Info("Default framerate set to %d.\n", default_fps);
+       }
+
+       if (size[0]) {
+               /* string; try matching with array */
+               for (sz = 0; sz < PSZ_MAX; sz++) {
+                       if (!strcmp(sizenames[sz], size)) { /* Found! */
+                               default_size = sz;
+                               break;
+                       }
+               }
+               if (sz == PSZ_MAX) {
+                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+                       return -EINVAL;
+               }
+               Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+       }
+       if (mbufs) {
+               if (mbufs < 1 || mbufs > MAX_IMAGES) {
+                       Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+                       return -EINVAL;
+               }
+               default_mbufs = mbufs;
+               Info("Number of image buffers set to %d.\n", default_mbufs);
+       }
+       if (fbufs) {
+               if (fbufs < 2 || fbufs > MAX_FRAMES) {
+                       Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+                       return -EINVAL;
+               }
+               default_fbufs = fbufs;
+               Info("Number of frame buffers set to %d.\n", default_fbufs);
+       }
+       if (trace >= 0) {
+               Info("Trace options: 0x%04x\n", trace);
+               pwc_trace = trace;
+       }
+       if (compression >= 0) {
+               if (compression > 3) {
+                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+                       return -EINVAL;
+               }
+               pwc_preferred_compression = compression;
+               Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+       }
+       if (power_save)
+               Info("Enabling power save on open/close.\n");
+       if (leds[0] >= 0)
+               led_on = leds[0];
+       if (leds[1] >= 0)
+               led_off = leds[1];
+
+       /* Big device node whoopla. Basically, it allows you to assign a
+          device node (/dev/videoX) to a camera, based on its type
+          & serial number. The format is [type[.serialnumber]:]node.
+
+          Any camera that isn't matched by these rules gets the next
+          available free device node.
+        */
+       for (i = 0; i < MAX_DEV_HINTS; i++) {
+               char *s, *colon, *dot;
+
+               /* This loop also initializes the array */
+               device_hint[i].pdev = NULL;
+               s = dev_hint[i];
+               if (s != NULL && *s != '\0') {
+                       device_hint[i].type = -1; /* wildcard */
+                       strcpy(device_hint[i].serial_number, "*");
+
+                       /* parse string: chop at ':' & '/' */
+                       colon = dot = s;
+                       while (*colon != '\0' && *colon != ':')
+                               colon++;
+                       while (*dot != '\0' && *dot != '.')
+                               dot++;
+                       /* Few sanity checks */
+                       if (*dot != '\0' && dot > colon) {
+                               Err("Malformed camera hint: the colon must be after the dot.\n");
+                               return -EINVAL;
+                       }
+
+                       if (*colon == '\0') {
+                               /* No colon */
+                               if (*dot != '\0') {
+                                       Err("Malformed camera hint: no colon + device node given.\n");
+                                       return -EINVAL;
+                               }
+                               else {
+                                       /* No type or serial number specified, just a number. */
+                                       device_hint[i].device_node = pwc_atoi(s);
+                               }
+                       }
+                       else {
+                               /* There's a colon, so we have at least a type and a device node */
+                               device_hint[i].type = pwc_atoi(s);
+                               device_hint[i].device_node = pwc_atoi(colon + 1);
+                               if (*dot != '\0') {
+                                       /* There's a serial number as well */
+                                       int k;
+
+                                       dot++;
+                                       k = 0;
+                                       while (*dot != ':' && k < 29) {
+                                               device_hint[i].serial_number[k++] = *dot;
+                                               dot++;
+                                       }
+                                       device_hint[i].serial_number[k] = '\0';
+                               }
+                       }
+#if PWC_DEBUG
+                       Debug("device_hint[%d]:\n", i);
+                       Debug("  type    : %d\n", device_hint[i].type);
+                       Debug("  serial# : %s\n", device_hint[i].serial_number);
+                       Debug("  node    : %d\n", device_hint[i].device_node);
+#endif
+               }
+               else
+                       device_hint[i].type = 0; /* not filled */
+       } /* ..for MAX_DEV_HINTS */
+
+       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+       return usb_register(&pwc_driver);
+}
+
+static void __exit usb_pwc_exit(void)
+{
+       Trace(TRACE_MODULE, "Deregistering driver.\n");
+       usb_deregister(&pwc_driver);
+       Info("Philips webcam module removed.\n");
+}
+
+module_init(usb_pwc_init);
+module_exit(usb_pwc_exit);
+
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h
new file mode 100644 (file)
index 0000000..784bc72
--- /dev/null
@@ -0,0 +1,292 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 8.12.1
+   It contains structures and defines to communicate from user space
+   directly to the driver.
+ */
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added ioctl constants to access methods for
+                         changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
+   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
+              PWCX easier
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+   They contain functions not found in other webcams, and settings not
+   specified in the Video4Linux API.
+
+   The #define names are built up like follows:
+   VIDIOC              VIDeo IOCtl prefix
+        PWC            Philps WebCam
+           G           optional: Get
+           S           optional: Set
+            ...        the function
+ */
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF      0x00
+#define PSZ_QSIF       0x01
+#define PSZ_QCIF       0x02
+#define PSZ_SIF                0x03
+#define PSZ_CIF                0x04
+#define PSZ_VGA                0x05
+#define PSZ_MAX                6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+   the upper 16 bits, since some flags are defined nowadays. The following
+   defines provide a mask and shift to filter out this value.
+
+   In 'Snapshot' mode the camera freezes its automatic exposure and colour
+   balance controls.
+ */
+#define PWC_FPS_SHIFT          16
+#define PWC_FPS_MASK           0x00FF0000
+#define PWC_FPS_FRMASK         0x003F0000
+#define PWC_FPS_SNAPSHOT       0x00400000
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+       int x, y;               /* guess what */
+       int size;               /* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+       char name[32];
+       int type;
+};
+
+struct pwc_serial
+{
+       char serial[30];        /* String with serial number. Contains terminating 0 */
+};
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR          0
+#define PWC_WB_OUTDOOR         1
+#define PWC_WB_FL              2
+#define PWC_WB_MANUAL          3
+#define PWC_WB_AUTO            4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+   Set mode to one of the PWC_WB_* values above.
+   *red and *blue are the respective gains of these colour components inside
+   the camera; range 0..65535
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
+   otherwise undefined.
+   'read_red' and 'read_blue' are read-only.
+*/
+struct pwc_whitebalance
+{
+       int mode;
+       int manual_red, manual_blue;    /* R/W */
+       int read_red, read_blue;        /* R/O */
+};
+
+/*
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+       int control_speed;
+       int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+       int led_on;                     /* Led on-time; range = 0..25000 */
+       int led_off;                    /* Led off-time; range = 0..25000  */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+       int width;
+       int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN            0x01
+#define PWC_MPT_TILT           0x02
+#define PWC_MPT_TIMEOUT                0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the
+   driver calculates the relative offset for you. This can only
+   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+   absolute angles.
+ */
+struct pwc_mpt_angles
+{
+       int absolute;           /* write-only */
+       int pan;                /* degrees * 100 */
+       int tilt;               /* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+       int pan_min, pan_max;           /* degrees * 100 */
+       int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+       int status;
+       int time_pan;
+       int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+   all the necessary information to initialize and use the decompressor
+   routines in standalone applications.
+ */
+struct pwc_video_command
+{
+       int type;               /* camera type (645, 675, 730, etc.) */
+       int release;            /* release number */
+
+       int size;               /* one of PSZ_* */
+       int alternate;
+       int command_len;        /* length of USB video command */
+       unsigned char command_buf[13];  /* Actual USB video command */
+       int bandlength;         /* >0 = compressed */
+       int frame_size;         /* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR       0x0001
+#define PWCX_FLAG_BAYER                0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER         _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER         _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY       _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+    means use uncompressed modes when available; 1 is low compression, 2 is
+    medium and 3 is high compression preferred. Of course, the higher the
+    compression, the lower the bandwidth used but more chance of artefacts
+    in the image. The driver automatically chooses a higher compression when
+    the preferred mode is not available.
+  */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */
+#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC          _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC          _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */
+#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+   int len;
+   char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
+
+#endif
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c
new file mode 100644 (file)
index 0000000..4c96037
--- /dev/null
@@ -0,0 +1,318 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/* This tables contains entries for the 730/740/750 (Kiara) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+
+#include "pwc-kiara.h"
+#include "pwc-uncompress.h"
+
+const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
+{
+   /* SQCIF */
+   {
+      /* 5 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+   },
+   /* QSIF */
+   {
+      /* 5 fps */
+      {
+        {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+        {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+        {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+        {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+      },
+      /* 10 fps */
+      {
+        {2, 291,    0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}},
+        {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+        {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+        {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+      },
+      /* 15 fps */
+      {
+        {3, 437,    0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}},
+        {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
+        {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
+        {1, 192,  420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
+      },
+      /* 20 fps */
+      {
+        {4, 589,    0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}},
+        {3, 448,  730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}},
+        {2, 292,  476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}},
+        {1, 192,  312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
+      },
+      /* 25 fps */
+      {
+        {5, 703,    0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}},
+        {3, 447,  610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}},
+        {2, 292,  398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}},
+        {1, 193,  262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}},
+      },
+      /* 30 fps */
+      {
+        {8, 874,    0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}},
+        {5, 704,  730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}},
+        {3, 448,  492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}},
+        {2, 292,  320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}},
+      },
+   },
+   /* QCIF */
+   {
+      /* 5 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+   },
+   /* SIF */
+   {
+      /* 5 fps */
+      {
+        {4, 582,    0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}},
+        {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}},
+        {2, 291,  960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}},
+        {1, 191,  630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}},
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}},
+        {3, 447,  736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}},
+        {2, 292,  480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}},
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}},
+        {4, 592,  650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}},
+        {3, 448,  492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}},
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {9, 958,  782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}},
+        {5, 703,  574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}},
+        {3, 446,  364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}},
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {9, 958,  654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}},
+        {6, 776,  530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}},
+        {4, 592,  404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}},
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {9, 957,  526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}},
+        {6, 775,  426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}},
+        {4, 590,  324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}},
+      },
+   },
+   /* CIF */
+   {
+      /* 5 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+   },
+   /* VGA */
+   {
+      /* 5 fps */
+      {
+        {0, },
+        {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}},
+        {4, 592,  976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}},
+        {3, 448,  738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}},
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {9, 956,  788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}},
+        {6, 776,  640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}},
+        {4, 592,  488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}},
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
+        {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
+        {8, 895,  492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}},
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+   },
+};
+
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
new file mode 100644 (file)
index 0000000..12929ab
--- /dev/null
@@ -0,0 +1,45 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* Entries for the Kiara (730/740/750) camera */
+
+#ifndef PWC_KIARA_H
+#define PWC_KIARA_H
+
+#include "pwc-ioctl.h"
+
+struct Kiara_table_entry
+{
+       char alternate;                 /* USB alternate interface */
+       unsigned short packetsize;      /* Normal packet size */
+       unsigned short bandlength;      /* Bandlength when decompressing */
+       unsigned char mode[12];         /* precomputed mode settings for cam */
+};
+
+const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+const extern unsigned int KiaraRomTable[8][2][16][8];
+
+#endif
+
+
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
new file mode 100644 (file)
index 0000000..58fe797
--- /dev/null
@@ -0,0 +1,140 @@
+/* Linux driver for Philips webcam
+   Various miscellaneous functions and tables.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/slab.h>
+
+#include "pwc.h"
+
+struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+{
+       { 128,  96, 0 },
+       { 160, 120, 0 },
+       { 176, 144, 0 },
+       { 320, 240, 0 },
+       { 352, 288, 0 },
+       { 640, 480, 0 },
+};
+
+/* x,y -> PSZ_ */
+int pwc_decode_size(struct pwc_device *pdev, int width, int height)
+{
+       int i, find;
+
+       /* Make sure we don't go beyond our max size.
+          NB: we have different limits for RAW and normal modes. In case
+          you don't have the decompressor loaded or use RAW mode,
+          the maximum viewable size is smaller.
+       */
+       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       {
+               if (width > pdev->abs_max.x || height > pdev->abs_max.y)
+               {
+                       Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+                       return -1;
+               }
+       }
+       else
+       {
+               if (width > pdev->view_max.x || height > pdev->view_max.y)
+               {
+                       Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+                       return -1;
+               }
+       }
+
+       /* Find the largest size supported by the camera that fits into the
+          requested size.
+        */
+       find = -1;
+       for (i = 0; i < PSZ_MAX; i++) {
+               if (pdev->image_mask & (1 << i)) {
+                       if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
+                               find = i;
+               }
+       }
+       return find;
+}
+
+/* initialize variables depending on type and decompressor*/
+void pwc_construct(struct pwc_device *pdev)
+{
+       switch(pdev->type) {
+       case 645:
+       case 646:
+               pdev->view_min.x = 128;
+               pdev->view_min.y =  96;
+               pdev->view_max.x = 352;
+               pdev->view_max.y = 288;
+               pdev->abs_max.x  = 352;
+               pdev->abs_max.y  = 288;
+               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
+               pdev->vcinterface = 2;
+               pdev->vendpoint = 4;
+               pdev->frame_header_size = 0;
+               pdev->frame_trailer_size = 0;
+               break;
+       case 675:
+       case 680:
+       case 690:
+               pdev->view_min.x = 128;
+               pdev->view_min.y =  96;
+               /* Anthill bug #38: PWC always reports max size, even without PWCX */
+               pdev->view_max.x = 640;
+               pdev->view_max.y = 480;
+               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
+               pdev->abs_max.x = 640;
+               pdev->abs_max.y = 480;
+               pdev->vcinterface = 3;
+               pdev->vendpoint = 4;
+               pdev->frame_header_size = 0;
+               pdev->frame_trailer_size = 0;
+               break;
+       case 720:
+       case 730:
+       case 740:
+       case 750:
+               pdev->view_min.x = 160;
+               pdev->view_min.y = 120;
+               pdev->view_max.x = 640;
+               pdev->view_max.y = 480;
+               pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+               pdev->abs_max.x = 640;
+               pdev->abs_max.y = 480;
+               pdev->vcinterface = 3;
+               pdev->vendpoint = 5;
+               pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+               pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+               break;
+       }
+       Debug("type = %d\n",pdev->type);
+       pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
+       pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
+       pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
+       /* length of image, in YUV format; always allocate enough memory. */
+       pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+}
+
+
diff --git a/drivers/media/video/pwc/pwc-nala.h b/drivers/media/video/pwc/pwc-nala.h
new file mode 100644 (file)
index 0000000..168c73e
--- /dev/null
@@ -0,0 +1,66 @@
+   /* SQCIF */
+   {
+      {0, 0, {0x04, 0x01, 0x03}},
+      {8, 0, {0x05, 0x01, 0x03}},
+      {7, 0, {0x08, 0x01, 0x03}},
+      {7, 0, {0x0A, 0x01, 0x03}},
+      {6, 0, {0x0C, 0x01, 0x03}},
+      {5, 0, {0x0F, 0x01, 0x03}},
+      {4, 0, {0x14, 0x01, 0x03}},
+      {3, 0, {0x18, 0x01, 0x03}},
+   },
+   /* QSIF */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
+   /* QCIF */
+   {
+      {0, 0, {0x04, 0x01, 0x02}},
+      {8, 0, {0x05, 0x01, 0x02}},
+      {7, 0, {0x08, 0x01, 0x02}},
+      {6, 0, {0x0A, 0x01, 0x02}},
+      {5, 0, {0x0C, 0x01, 0x02}},
+      {4, 0, {0x0F, 0x01, 0x02}},
+      {1, 0, {0x14, 0x01, 0x02}},
+      {1, 0, {0x18, 0x01, 0x02}},
+   },
+   /* SIF */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
+   /* CIF */
+   {
+      {4, 0, {0x04, 0x01, 0x01}},
+      {7, 1, {0x05, 0x03, 0x01}},
+      {6, 1, {0x08, 0x03, 0x01}},
+      {4, 1, {0x0A, 0x03, 0x01}},
+      {3, 1, {0x0C, 0x03, 0x01}},
+      {2, 1, {0x0F, 0x03, 0x01}},
+      {0},
+      {0},
+   },
+   /* VGA */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c
new file mode 100644 (file)
index 0000000..175250d
--- /dev/null
@@ -0,0 +1,316 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/* This tables contains entries for the 675/680/690 (Timon) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+#include "pwc-timon.h"
+
+const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
+{
+   /* SQCIF */
+   {
+      /* 5 fps */
+      {
+        {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+        {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+        {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+        {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+      },
+      /* 10 fps */
+      {
+        {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+        {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+        {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+        {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+      },
+      /* 15 fps */
+      {
+        {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+        {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+        {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+        {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+      },
+      /* 20 fps */
+      {
+        {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+        {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+        {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+        {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+      },
+      /* 25 fps */
+      {
+        {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+        {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+        {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+        {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+      },
+      /* 30 fps */
+      {
+        {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+        {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+        {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+        {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+      },
+   },
+   /* QSIF */
+   {
+      /* 5 fps */
+      {
+        {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+        {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+        {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+        {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+      },
+      /* 10 fps */
+      {
+        {2, 291,    0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}},
+        {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+        {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+        {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+      },
+      /* 15 fps */
+      {
+        {3, 437,    0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}},
+        {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+        {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+        {1, 191,  420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+      },
+      /* 20 fps */
+      {
+        {4, 588,    0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}},
+        {3, 447,  730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+        {2, 292,  476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+        {1, 192,  312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
+      },
+      /* 25 fps */
+      {
+        {5, 703,    0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}},
+        {3, 447,  610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+        {2, 292,  398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+        {1, 192,  262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+        {8, 873,    0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}},
+        {5, 704,  774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}},
+        {3, 448,  492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}},
+        {2, 291,  320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
+      },
+   },
+   /* QCIF */
+   {
+      /* 5 fps */
+      {
+        {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+        {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+        {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+        {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+      },
+      /* 10 fps */
+      {
+        {3, 385,    0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}},
+        {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+        {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+        {1, 194,  532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}},
+      },
+      /* 15 fps */
+      {
+        {4, 577,    0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}},
+        {3, 447,  818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}},
+        {2, 292,  534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}},
+        {1, 195,  356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}},
+      },
+      /* 20 fps */
+      {
+        {6, 776,    0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}},
+        {4, 591,  804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}},
+        {3, 447,  608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+        {2, 291,  396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
+      },
+      /* 25 fps */
+      {
+        {9, 928,    0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}},
+        {5, 703,  800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}},
+        {3, 447,  508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+        {2, 292,  332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {9, 956,  876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}},
+        {4, 592,  542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}},
+        {2, 291,  266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}},
+      },
+   },
+   /* SIF */
+   {
+      /* 5 fps */
+      {
+        {4, 582,    0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}},
+        {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}},
+        {2, 291,  960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}},
+        {1, 191,  630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}},
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}},
+        {3, 447,  736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}},
+        {2, 291,  480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}},
+        {4, 591,  650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}},
+        {3, 448,  492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}},
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {9, 958,  782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}},
+        {5, 703,  574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}},
+        {3, 446,  364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}},
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {9, 958,  654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}},
+        {6, 776,  530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}},
+        {4, 592,  404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}},
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {9, 957,  526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}},
+        {6, 775,  426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}},
+        {4, 590,  324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}},
+      },
+   },
+   /* CIF */
+   {
+      /* 5 fps */
+      {
+        {6, 771,    0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}},
+        {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}},
+        {2, 291,  800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}},
+        {1, 193,  528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}},
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}},
+        {4, 591,  812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}},
+        {2, 291,  400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {9, 956,  876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}},
+        {5, 703,  644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}},
+        {3, 448,  410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}},
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {9, 956,  650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}},
+        {6, 776,  528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}},
+        {4, 591,  402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}},
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {9, 956,  544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}},
+        {7, 840,  478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}},
+        {5, 703,  400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {9, 956,  438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}},
+        {7, 838,  384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}},
+        {6, 773,  354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}},
+      },
+   },
+   /* VGA */
+   {
+      /* 5 fps */
+      {
+        {0, },
+        {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}},
+        {4, 592,  976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}},
+        {3, 448,  738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}},
+      },
+      /* 10 fps */
+      {
+        {0, },
+        {9, 956,  788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}},
+        {6, 776,  640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}},
+        {4, 592,  488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+        {0, },
+        {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
+        {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
+        {8, 895,  492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}},
+      },
+      /* 20 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 25 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+      /* 30 fps */
+      {
+        {0, },
+        {0, },
+        {0, },
+        {0, },
+      },
+   },
+};
+
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
new file mode 100644 (file)
index 0000000..a86b378
--- /dev/null
@@ -0,0 +1,61 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+
+/* This tables contains entries for the 675/680/690 (Timon) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+#ifndef PWC_TIMON_H
+#define PWC_TIMON_H
+
+#include "pwc-ioctl.h"
+
+struct Timon_table_entry
+{
+       char alternate;                 /* USB alternate interface */
+       unsigned short packetsize;      /* Normal packet size */
+       unsigned short bandlength;      /* Bandlength when decompressing */
+       unsigned char mode[13];         /* precomputed mode settings for cam */
+};
+
+const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+const extern unsigned int TimonRomTable [16][2][16][8];
+
+
+#endif
+
+
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
new file mode 100644 (file)
index 0000000..b37a89a
--- /dev/null
@@ -0,0 +1,146 @@
+/* Linux driver for Philips webcam
+   Decompression frontend.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <asm/current.h>
+#include <asm/types.h>
+
+#include "pwc.h"
+#include "pwc-uncompress.h"
+
+int pwc_decompress(struct pwc_device *pdev)
+{
+       struct pwc_frame_buf *fbuf;
+       int n, line, col, stride;
+       void *yuv, *image;
+       u16 *src;
+       u16 *dsty, *dstu, *dstv;
+
+       if (pdev == NULL)
+               return -EFAULT;
+#if defined(__KERNEL__) && defined(PWC_MAGIC)
+       if (pdev->magic != PWC_MAGIC) {
+               Err("pwc_decompress(): magic failed.\n");
+               return -EFAULT;
+       }
+#endif
+
+       fbuf = pdev->read_frame;
+       if (fbuf == NULL)
+               return -EFAULT;
+       image = pdev->image_ptr[pdev->fill_image];
+       if (!image)
+               return -EFAULT;
+
+       yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
+
+       /* Raw format; that's easy... */
+       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       {
+               memcpy(image, yuv, pdev->frame_size);
+               return 0;
+       }
+
+       if (pdev->vbandlength == 0) {
+               /* Uncompressed mode. We copy the data into the output buffer,
+                  using the viewport size (which may be larger than the image
+                  size). Unfortunately we have to do a bit of byte stuffing
+                  to get the desired output format/size.
+                */
+                       /*
+                        * We do some byte shuffling here to go from the
+                        * native format to YUV420P.
+                        */
+                       src = (u16 *)yuv;
+                       n = pdev->view.x * pdev->view.y;
+
+                       /* offset in Y plane */
+                       stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+                       dsty = (u16 *)(image + stride);
+
+                       /* offsets in U/V planes */
+                       stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+                       dstu = (u16 *)(image + n +         stride);
+                       dstv = (u16 *)(image + n + n / 4 + stride);
+
+                       /* increment after each line */
+                       stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+                       for (line = 0; line < pdev->image.y; line++) {
+                               for (col = 0; col < pdev->image.x; col += 4) {
+                                       *dsty++ = *src++;
+                                       *dsty++ = *src++;
+                                       if (line & 1)
+                                               *dstv++ = *src++;
+                                       else
+                                               *dstu++ = *src++;
+                               }
+                               dsty += stride;
+                               if (line & 1)
+                                       dstv += (stride >> 1);
+                               else
+                                       dstu += (stride >> 1);
+                       }
+       }
+       else {
+               /* Compressed; the decompressor routines will write the data
+                  in planar format immediately.
+                */
+               int flags;
+
+               flags = PWCX_FLAG_PLANAR;
+               if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
+                {
+                  printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
+                  flags |= PWCX_FLAG_BAYER;
+                  return -ENXIO; /* No such device or address: missing decompressor */
+                }
+
+#if 0
+               switch (pdev->type)
+                {
+                 case 675:
+                 case 680:
+                 case 690:
+                 case 720:
+                 case 730:
+                 case 740:
+                 case 750:
+                   pwc_dec23_decompress(&pdev->image, &pdev->view,
+                               &pdev->offset, yuv, image, flags,
+                               pdev->decompress_data, pdev->vbandlength);
+                   break;
+                 case 645:
+                 case 646:
+                   /* TODO & FIXME */
+                   return -ENXIO; /* Missing decompressor */
+                   break;
+                }
+#endif
+       }
+       return 0;
+}
+
+
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
new file mode 100644 (file)
index 0000000..f75e1b6
--- /dev/null
@@ -0,0 +1,41 @@
+/* (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This file is the bridge between the kernel module and the plugin; it
+   describes the structures and datatypes used in both modules. Any
+   significant change should be reflected by increasing the
+   pwc_decompressor_version major number.
+ */
+#ifndef PWC_UNCOMPRESS_H
+#define PWC_UNCOMPRESS_H
+
+#include <linux/config.h>
+
+#include "pwc-ioctl.h"
+
+/* from pwc-dec.h */
+#define PWCX_FLAG_PLANAR        0x0001
+/* */
+
+#endif
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
new file mode 100644 (file)
index 0000000..1b0ee0c
--- /dev/null
@@ -0,0 +1,272 @@
+/* (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef PWC_H
+#define PWC_H
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <linux/videodev.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+#include "pwc-uncompress.h"
+#include "pwc-ioctl.h"
+
+/* Defines and structures for the Philips webcam */
+/* Used for checking memory corruption/pointer validation */
+#define PWC_MAGIC 0x89DC10ABUL
+#undef PWC_MAGIC
+
+/* Turn some debugging options on/off */
+#define PWC_DEBUG 0
+
+/* Trace certain actions in the driver */
+#define TRACE_MODULE   0x0001
+#define TRACE_PROBE    0x0002
+#define TRACE_OPEN     0x0004
+#define TRACE_READ     0x0008
+#define TRACE_MEMORY   0x0010
+#define TRACE_FLOW     0x0020
+#define TRACE_SIZE     0x0040
+#define TRACE_PWCX     0x0080
+#define TRACE_SEQUENCE 0x1000
+
+#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
+#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
+#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
+#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
+
+
+/* Defines for ToUCam cameras */
+#define TOUCAM_HEADER_SIZE             8
+#define TOUCAM_TRAILER_SIZE            4
+
+#define FEATURE_MOTOR_PANTILT          0x0001
+
+/* Version block */
+#define PWC_MAJOR      9
+#define PWC_MINOR      0
+#define PWC_VERSION    "9.0.2-unofficial"
+#define PWC_NAME       "pwc"
+
+/* Turn certain features on/off */
+#define PWC_INT_PIPE 0
+
+/* Ignore errors in the first N frames, to allow for startup delays */
+#define FRAME_LOWMARK 5
+
+/* Size and number of buffers for the ISO pipe. */
+#define MAX_ISO_BUFS           2
+#define ISO_FRAMES_PER_DESC    10
+#define ISO_MAX_FRAME_SIZE     960
+#define ISO_BUFFER_SIZE        (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
+
+/* Frame buffers: contains compressed or uncompressed video data. */
+#define MAX_FRAMES             5
+/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
+#define PWC_FRAME_SIZE                 (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
+
+/* Absolute maximum number of buffers available for mmap() */
+#define MAX_IMAGES             10
+
+/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
+struct pwc_iso_buf
+{
+       void *data;
+       int  length;
+       int  read;
+       struct urb *urb;
+};
+
+/* intermediate buffers with raw data from the USB cam */
+struct pwc_frame_buf
+{
+   void *data;
+   volatile int filled;                /* number of bytes filled */
+   struct pwc_frame_buf *next; /* list */
+#if PWC_DEBUG
+   int sequence;               /* Sequence number */
+#endif
+};
+
+struct pwc_device
+{
+   struct video_device *vdev;
+#ifdef PWC_MAGIC
+   int magic;
+#endif
+   /* Pointer to our usb_device */
+   struct usb_device *udev;
+
+   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
+   int release;                        /* release number */
+   int features;               /* feature bits */
+   char serial[30];            /* serial number (string) */
+   int error_status;           /* set when something goes wrong with the cam (unplugged, USB errors) */
+   int usb_init;               /* set when the cam has been initialized over USB */
+
+   /*** Video data ***/
+   int vopen;                  /* flag */
+   int vendpoint;              /* video isoc endpoint */
+   int vcinterface;            /* video control interface */
+   int valternate;             /* alternate interface needed */
+   int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
+   int vpalette;               /* palette: 420P, RAW or RGBBAYER */
+   int vframe_count;           /* received frames */
+   int vframes_dumped;                 /* counter for dumped frames */
+   int vframes_error;          /* frames received in error */
+   int vmax_packet_size;       /* USB maxpacket size */
+   int vlast_packet_size;      /* for frame synchronisation */
+   int visoc_errors;           /* number of contiguous ISOC errors */
+   int vcompression;           /* desired compression factor */
+   int vbandlength;            /* compressed band length; 0 is uncompressed */
+   char vsnapshot;             /* snapshot mode */
+   char vsync;                 /* used by isoc handler */
+   char vmirror;               /* for ToUCaM series */
+
+   int cmd_len;
+   unsigned char cmd_buf[13];
+
+   /* The image acquisition requires 3 to 4 steps:
+      1. data is gathered in short packets from the USB controller
+      2. data is synchronized and packed into a frame buffer
+      3a. in case data is compressed, decompress it directly into image buffer
+      3b. in case data is uncompressed, copy into image buffer with viewport
+      4. data is transferred to the user process
+
+      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
+      We have in effect a back-to-back-double-buffer system.
+    */
+   /* 1: isoc */
+   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
+   char iso_init;
+
+   /* 2: frame */
+   struct pwc_frame_buf *fbuf; /* all frames */
+   struct pwc_frame_buf *empty_frames, *empty_frames_tail;     /* all empty frames */
+   struct pwc_frame_buf *full_frames, *full_frames_tail;       /* all filled frames */
+   struct pwc_frame_buf *fill_frame;   /* frame currently being filled */
+   struct pwc_frame_buf *read_frame;   /* frame currently read by user process */
+   int frame_header_size, frame_trailer_size;
+   int frame_size;
+   int frame_total_size; /* including header & trailer */
+   int drop_frames;
+#if PWC_DEBUG
+   int sequence;                       /* Debugging aid */
+#endif
+
+   /* 3: decompression */
+   struct pwc_decompressor *decompressor;      /* function block with decompression routines */
+   void *decompress_data;              /* private data for decompression engine */
+
+   /* 4: image */
+   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
+      as delivered by the camera, and 'view' is the size requested by the
+      program. The camera image is centered in this viewport, laced with
+      a gray or black border. view_min <= image <= view <= view_max;
+    */
+   int image_mask;                     /* bitmask of supported sizes */
+   struct pwc_coord view_min, view_max;        /* minimum and maximum viewable sizes */
+   struct pwc_coord abs_max;            /* maximum supported size with compression */
+   struct pwc_coord image, view;       /* image and viewport size */
+   struct pwc_coord offset;            /* offset within the viewport */
+
+   void *image_data;                   /* total buffer, which is subdivided into ... */
+   void *image_ptr[MAX_IMAGES];                /* ...several images... */
+   int fill_image;                     /* ...which are rotated. */
+   int len_per_image;                  /* length per image */
+   int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
+   int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
+
+   struct semaphore modlock;           /* to prevent races in video_open(), etc */
+   spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
+
+   /*** motorized pan/tilt feature */
+   struct pwc_mpt_range angle_range;
+   int pan_angle;                      /* in degrees * 100 */
+   int tilt_angle;                     /* absolute angle; 0,0 is home position */
+
+   /*** Misc. data ***/
+   wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
+#if PWC_INT_PIPE
+   void *usb_int_handler;              /* for the interrupt endpoint */
+#endif
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global variable */
+extern int pwc_trace;
+
+/** functions in pwc-if.c */
+int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+
+/** Functions in pwc-misc.c */
+/* sizes in pixels */
+extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+
+int pwc_decode_size(struct pwc_device *pdev, int width, int height);
+void pwc_construct(struct pwc_device *pdev);
+
+/** Functions in pwc-ctrl.c */
+/* Request a certain video mode. Returns < 0 if not possible */
+extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+
+/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
+extern int pwc_get_brightness(struct pwc_device *pdev);
+extern int pwc_set_brightness(struct pwc_device *pdev, int value);
+extern int pwc_get_contrast(struct pwc_device *pdev);
+extern int pwc_set_contrast(struct pwc_device *pdev, int value);
+extern int pwc_get_gamma(struct pwc_device *pdev);
+extern int pwc_set_gamma(struct pwc_device *pdev, int value);
+extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_set_saturation(struct pwc_device *pdev, int value);
+extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
+extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+
+/* Power down or up the camera; not supported by all models */
+extern int pwc_camera_power(struct pwc_device *pdev, int power);
+
+/* Private ioctl()s; see pwc-ioctl.h */
+extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+
+
+/** pwc-uncompress.c */
+/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
+extern int pwc_decompress(struct pwc_device *pdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/drivers/media/video/rds.h b/drivers/media/video/rds.h
deleted file mode 100644 (file)
index 0d30eb7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-
-    Types and defines needed for RDS. This is included by
-    saa6588.c and every driver (e.g. bttv-driver.c) that wants
-    to use the saa6588 module.
-
-    Instead of having a seperate rds.h, I'd prefer to include
-    this stuff in one of the already existing files like tuner.h
-
-    (c) 2005 by Hans J. Koch
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef _RDS_H
-#define _RDS_H
-
-struct rds_command {
-       unsigned int  block_count;
-       int           result;
-       unsigned char __user *buffer;
-       struct file   *instance;
-       poll_table    *event_list;
-};
-
-#define RDS_CMD_OPEN   _IOW('R',1,int)
-#define RDS_CMD_CLOSE  _IOW('R',2,int)
-#define RDS_CMD_READ   _IOR('R',3,int)
-#define RDS_CMD_POLL   _IOR('R',4,int)
-
-#endif
-
-
-
-
index a9f3cf0b1e3c5b6044586e103627df0f0427d323..531e9461cb66d4fdbc7ab03f6941e4af2d8d43a9 100644 (file)
@@ -71,7 +71,7 @@
 #define NUM_BUFS 8
 #define IF_NAME "SAA5249"
 
-static const int disp_modes[8][3] = 
+static const int disp_modes[8][3] =
 {
        { 0x46, 0x03, 0x03 },   /* DISPOFF */
        { 0x46, 0xcc, 0xcc },   /* DISPNORM */
@@ -150,8 +150,8 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
        client=kmalloc(sizeof(*client), GFP_KERNEL);
        if(client==NULL)
                return -ENOMEM;
-        client_template.adapter = adap;
-        client_template.addr = addr;
+       client_template.adapter = adap;
+       client_template.addr = addr;
        memcpy(client, &client_template, sizeof(*client));
        t = kzalloc(sizeof(*t), GFP_KERNEL);
        if(t==NULL)
@@ -161,11 +161,11 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
        }
        strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
        mutex_init(&t->lock);
-       
+
        /*
         *      Now create a video4linux device
         */
-        
+
        vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
        if(vd==NULL)
        {
@@ -175,8 +175,8 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
        }
        i2c_set_clientdata(client, vd);
        memcpy(vd, &saa_template, sizeof(*vd));
-               
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) 
+
+       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
        {
                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
@@ -186,9 +186,9 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
                t->vdau[pgbuf].stopped = TRUE;
                t->is_searching[pgbuf] = FALSE;
        }
-       vd->priv=t;     
-        
-       
+       vd->priv=t;
+
+
        /*
         *      Register it
         */
@@ -208,7 +208,7 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
 /*
  *     We do most of the hard work when we become a device on the i2c.
  */
+
 static int saa5249_probe(struct i2c_adapter *adap)
 {
        if (adap->class & I2C_CLASS_TV_ANALOG)
@@ -229,7 +229,7 @@ static int saa5249_detach(struct i2c_client *client)
 
 /* new I2C driver support */
 
-static struct i2c_driver i2c_driver_videotext = 
+static struct i2c_driver i2c_driver_videotext =
 {
        .driver = {
                .name   = IF_NAME,              /* name */
@@ -249,7 +249,7 @@ static struct i2c_client client_template = {
  *     delay may be longer.
  */
 
-static void jdelay(unsigned long delay) 
+static void jdelay(unsigned long delay)
 {
        sigset_t oldblocked = current->blocked;
 
@@ -269,14 +269,14 @@ static void jdelay(unsigned long delay)
 /*
  *     I2C interfaces
  */
-static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data) 
+
+static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
 {
        char buf[64];
-       
+
        buf[0] = reg;
        memcpy(buf+1, data, count);
-       
+
        if(i2c_master_send(t->client, buf, count+1)==count+1)
                return 0;
        return -1;
@@ -289,7 +289,7 @@ static int i2c_senddata(struct saa5249_device *t, ...)
        int ct=0;
        va_list argp;
        va_start(argp,t);
-       
+
        while((v=va_arg(argp,int))!=-1)
                buf[ct++]=v;
        return i2c_sendbuf(t, buf[0], ct-1, buf+1);
@@ -301,7 +301,7 @@ static int i2c_senddata(struct saa5249_device *t, ...)
  * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
  */
 
-static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf) 
+static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
 {
        if(i2c_master_recv(t->client, buf, count)!=count)
                return -1;
@@ -320,9 +320,9 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
        struct video_device *vd = video_devdata(file);
        struct saa5249_device *t=vd->priv;
 
-       switch(cmd) 
+       switch(cmd)
        {
-               case VTXIOCGETINFO: 
+               case VTXIOCGETINFO:
                {
                        vtx_info_t *info = arg;
                        info->version_major = VTX_VER_MAJ;
@@ -332,10 +332,10 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
 
-               case VTXIOCCLRPAGE: 
+               case VTXIOCCLRPAGE:
                {
                        vtx_pagereq_t *req = arg;
-      
+
                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
                                return -EINVAL;
                        memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
@@ -343,17 +343,17 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
 
-               case VTXIOCCLRFOUND: 
+               case VTXIOCCLRFOUND:
                {
                        vtx_pagereq_t *req = arg;
-      
+
                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
                                return -EINVAL;
                        t->vdau[req->pgbuf].clrfound = TRUE;
                        return 0;
                }
 
-               case VTXIOCPAGEREQ: 
+               case VTXIOCPAGEREQ:
                {
                        vtx_pagereq_t *req = arg;
                        if (!(req->pagemask & PGMASK_PAGE))
@@ -381,7 +381,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
 
-               case VTXIOCGETSTAT: 
+               case VTXIOCGETSTAT:
                {
                        vtx_pagereq_t *req = arg;
                        u8 infobits[10];
@@ -390,7 +390,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
 
                        if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
                                return -EINVAL;
-                       if (!t->vdau[req->pgbuf].stopped) 
+                       if (!t->vdau[req->pgbuf].stopped)
                        {
                                if (i2c_senddata(t, 2, 0, -1) ||
                                        i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
@@ -403,7 +403,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                        return -EIO;
 
                                if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&   /* check FOUND-bit */
-                                       (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) || 
+                                       (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
                                        time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
                                {               /* check if new page arrived */
                                        if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
@@ -411,7 +411,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                                return -EIO;
                                        t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
                                        memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
-                                       if (t->virtual_mode) 
+                                       if (t->virtual_mode)
                                        {
                                                /* Packet X/24 */
                                                if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
@@ -459,9 +459,9 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        info.notfound = !!(infobits[8] & 0x10);
                        info.pblf = !!(infobits[9] & 0x20);
                        info.hamming = 0;
-                       for (a = 0; a <= 7; a++) 
+                       for (a = 0; a <= 7; a++)
                        {
-                               if (infobits[a] & 0xf0) 
+                               if (infobits[a] & 0xf0)
                                {
                                        info.hamming = 1;
                                        break;
@@ -471,14 +471,14 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                info.notfound = 1;
                        if(copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
                                return -EFAULT;
-                       if (!info.hamming && !info.notfound) 
+                       if (!info.hamming && !info.notfound)
                        {
                                t->is_searching[req->pgbuf] = FALSE;
                        }
                        return 0;
                }
 
-               case VTXIOCGETPAGE: 
+               case VTXIOCGETPAGE:
                {
                        vtx_pagereq_t *req = arg;
                        int start, end;
@@ -488,15 +488,15 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        if(copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
                                return -EFAULT;
-                               
-                        /* 
+
+                        /*
                          *     Always read the time directly from SAA5249
                          */
-                         
-                       if (req->start <= 39 && req->end >= 32) 
+
+                       if (req->start <= 39 && req->end >= 32)
                        {
                                int len;
-                               char buf[16];  
+                               char buf[16];
                                start = max(req->start, 32);
                                end = min(req->end, 39);
                                len=end-start+1;
@@ -507,7 +507,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                                        return -EFAULT;
                        }
                        /* Insert the current header if DAU is still searching for a page */
-                       if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) 
+                       if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf])
                        {
                                char buf[32];
                                int len;
@@ -523,7 +523,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
 
-               case VTXIOCSTOPDAU: 
+               case VTXIOCSTOPDAU:
                {
                        vtx_pagereq_t *req = arg;
 
@@ -534,12 +534,12 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
 
-               case VTXIOCPUTPAGE: 
-               case VTXIOCSETDISP: 
-               case VTXIOCPUTSTAT: 
+               case VTXIOCPUTPAGE:
+               case VTXIOCSETDISP:
+               case VTXIOCPUTSTAT:
                        return 0;
-                       
-               case VTXIOCCLRCACHE: 
+
+               case VTXIOCCLRCACHE:
                {
                        if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
                                ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
@@ -551,7 +551,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
                        return 0;
                }
 
-               case VTXIOCSETVIRT: 
+               case VTXIOCSETVIRT:
                {
                        /* The SAA5249 has virtual-row reception turned on always */
                        t->virtual_mode = (int)(long)arg;
@@ -612,14 +612,14 @@ static inline unsigned int vtx_fix_command(unsigned int cmd)
 /*
  *     Handle the locking
  */
+
 static int saa5249_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg) 
+                        unsigned int cmd, unsigned long arg)
 {
        struct video_device *vd = video_devdata(file);
        struct saa5249_device *t=vd->priv;
        int err;
-       
+
        cmd = vtx_fix_command(cmd);
        mutex_lock(&t->lock);
        err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
@@ -627,7 +627,7 @@ static int saa5249_ioctl(struct inode *inode, struct file *file,
        return err;
 }
 
-static int saa5249_open(struct inode *inode, struct file *file) 
+static int saa5249_open(struct inode *inode, struct file *file)
 {
        struct video_device *vd = video_devdata(file);
        struct saa5249_device *t=vd->priv;
@@ -636,7 +636,7 @@ static int saa5249_open(struct inode *inode, struct file *file)
        err = video_exclusive_open(inode,file);
        if (err < 0)
                return err;
-       
+
        if (t->client==NULL) {
                err = -ENODEV;
                goto fail;
@@ -647,13 +647,13 @@ static int saa5249_open(struct inode *inode, struct file *file)
                i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
                                                /* Display TV-picture, no virtual rows */
                i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */
-       
+
        {
                err = -EIO;
                goto fail;
        }
 
-       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) 
+       for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
        {
                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
@@ -673,7 +673,7 @@ static int saa5249_open(struct inode *inode, struct file *file)
 
 
 
-static int saa5249_release(struct inode *inode, struct file *file) 
+static int saa5249_release(struct inode *inode, struct file *file)
 {
        struct video_device *vd = video_devdata(file);
        struct saa5249_device *t=vd->priv;
@@ -690,7 +690,7 @@ static int __init init_saa_5249 (void)
        return i2c_add_driver(&i2c_driver_videotext);
 }
 
-static void __exit cleanup_saa_5249 (void) 
+static void __exit cleanup_saa_5249 (void)
 {
        i2c_del_driver(&i2c_driver_videotext);
 }
index d17395c4f55cb9a17b1e2e5adb0b6bc00df85cf5..a81285ca7d5bcbb98d54f8bb326536e064442815 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/uaccess.h>
 
 
-#include "rds.h"
+#include <media/rds.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {
index e18ea268384bda2599f3150946d12aaa8b19b453..41d951db6ec0f34c731644d6dfa74b71dc8b8519 100644 (file)
@@ -139,7 +139,7 @@ saa7110_read (struct i2c_client *client)
 
 static int
 saa7110_selmux (struct i2c_client *client,
-               int                chan)
+               int                chan)
 {
        static const unsigned char modes[9][8] = {
                /* mode 0 */
@@ -457,7 +457,7 @@ static unsigned short normal_i2c[] = {
 };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
index f9ba0c943adf0543e872a22d155e37b13b69377a..686fd4746205385c23c8b6b53731e37df5de7287 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * saa7111 - Philips SAA7111A video decoder driver version 0.0.3
  *
  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
@@ -482,7 +482,7 @@ saa7111_command (struct i2c_client *client,
 static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
index 4a1f841d0c770cf68eb148cf7acb30618f072ba5..90398ab8252e62053a6fcf54e41af77a31500d9a 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * saa7114 - Philips SAA7114H video decoder driver version 0.0.1
  *
  * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
@@ -300,7 +300,7 @@ static const unsigned char init[] = {
        0x55, 0xff,
        0x56, 0xff,
        0x57, 0xff,
-       0x58, 0x40,             // framing code 
+       0x58, 0x40,             // framing code
        0x59, 0x47,             // horizontal offset
        0x5a, 0x06,             // vertical offset
        0x5b, 0x83,             // field offset
@@ -345,7 +345,7 @@ static const unsigned char init[] = {
        0x82, 0x00,
        0x83, 0x00,
        0x84, 0xc5,
-       0x85, 0x0d,             // hsync and vsync ? 
+       0x85, 0x0d,             // hsync and vsync ?
        0x86, 0x40,
        0x87, 0x01,
        0x88, 0x00,
@@ -434,7 +434,7 @@ static const unsigned char init[] = {
        0xd9, 0x04,
        0xda, 0x00,             // horizontal luminance phase offset
        0xdb, 0x00,
-       0xdc, 0x00,             // horizontal chrominance scaling increment 
+       0xdc, 0x00,             // horizontal chrominance scaling increment
        0xdd, 0x02,
        0xde, 0x00,             // horizontal chrominance phase offset
        0xdf, 0x00,
@@ -754,7 +754,7 @@ saa7114_command (struct i2c_client *client,
                        saa7114_write(client, 0x87,
                                      decoder->reg[REG_ADDR(0x87)]);
                        saa7114_write(client, 0x88, 0xd8);      // sw reset scaler
-                       saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release            
+                       saa7114_write(client, 0x88, 0xf8);      // sw reset scaler release
                        saa7114_write(client, 0x80, 0x36);
 
                }
@@ -813,7 +813,7 @@ static unsigned short normal_i2c[] =
     { I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
index b184fd00b4e779270f41f0625fe331fa68b5466d..b05015282601d37dbd7243332f26d8b8fcdc008e 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
-#include <media/audiochip.h>
 #include <asm/div64.h>
 
 MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
index 74e37d405208030b929219b658122a2050a35e39..66967ae374940f67c528abc32f43a8ca9de9abf8 100644 (file)
@@ -64,7 +64,7 @@
 #define PAL_MSB_VERTICAL       0x40    /* 7c */
 
 /* Initialization Sequence */
-        
+
 static __u8 init7121ntsc[] = {
        0x26, 0x0,      0x27, 0x0,
        0x28, NTSC_BURST_START,         0x29, NTSC_BURST_END,
@@ -95,7 +95,7 @@ static __u8 init7121ntsc[] = {
        0x78, 0x0,      0x79, 0x0,      0x7a, NTSC_FIRST_ACTIVE,
        0x7b, NTSC_LAST_ACTIVE,         0x7c, NTSC_MSB_VERTICAL,
        0x7d, 0x0,      0x7e, 0x0,      0x7f, 0x0
-}; 
+};
 #define INIT7121LEN    (sizeof(init7121ntsc)/2)
 
 static __u8 init7121pal[] = {
@@ -128,5 +128,5 @@ static __u8 init7121pal[] = {
        0x78, 0x0,      0x79, 0x0,      0x7a, PAL_FIRST_ACTIVE,
        0x7b, PAL_LAST_ACTIVE,          0x7c, PAL_MSB_VERTICAL,
        0x7d, 0x0,      0x7e, 0x0,      0x7f, 0x0
-}; 
+};
 #endif
index aca84d2f9825dbaa9285551dbe6eeeba95aebccc..bb3e0ba946d34b2eb2b854a25b8b44f1a4a06e55 100644 (file)
@@ -507,7 +507,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
        /* release the old buffer */
        if (substream->runtime->dma_area) {
                saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-               videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+               videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                substream->runtime->dma_area = NULL;
        }
@@ -523,12 +523,12 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
                return err;
        }
 
-       if (0 != (err = videobuf_dma_pci_map(dev->pci, &dev->dmasound.dma))) {
+       if (0 != (err = videobuf_pci_dma_map(dev->pci, &dev->dmasound.dma))) {
                dsp_buffer_free(dev);
                return err;
        }
        if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
-               videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+               videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                return err;
        }
@@ -537,7 +537,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
                                                dev->dmasound.dma.sglen,
                                                0))) {
                saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-               videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+               videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                return err;
        }
@@ -571,7 +571,7 @@ static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
 
        if (substream->runtime->dma_area) {
                saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
-               videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+               videobuf_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
                dsp_buffer_free(dev);
                substream->runtime->dma_area = NULL;
        }
index 58e568d7d2ee2b7545920dcb775f07a64c4de50f..c98571c9d5a639df1470003475f07c281580727f 100644 (file)
@@ -254,12 +254,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
 
 /* ------------------------------------------------------------------ */
 
-void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf)
+void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
 {
        BUG_ON(in_interrupt());
 
        videobuf_waiton(&buf->vb,0,0);
-       videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
+       videobuf_dma_unmap(q, &buf->vb.dma);
        videobuf_dma_free(&buf->vb.dma);
        buf->vb.state = STATE_NEEDS_INIT;
 }
@@ -960,7 +960,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        if (saa7134_no_overlay <= 0) {
                saa7134_video_template.type |= VID_TYPE_OVERLAY;
        } else {
-               printk("bttv: Overlay support disabled.\n");
+               printk("%s: Overlay support disabled.\n",dev->name);
        }
        dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
        err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
index d79d05f88705026216e2efa3aa9a2de786268d32..7aa02b34e012f37254d15d3853437ef0b8c6d9af 100644 (file)
@@ -124,7 +124,7 @@ static int dsp_rec_start(struct saa7134_dev *dev)
        unsigned long flags;
 
        /* prepare buffer */
-       if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
+       if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma)))
                return err;
        if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
                goto fail1;
@@ -213,7 +213,7 @@ static int dsp_rec_start(struct saa7134_dev *dev)
  fail2:
        saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
  fail1:
-       videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+       videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
        return err;
 }
 
@@ -231,7 +231,7 @@ static int dsp_rec_stop(struct saa7134_dev *dev)
 
        /* unlock buffer */
        saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
-       videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+       videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
        return 0;
 }
 
index 470903e2f5e54ae51587a29f19e1557c3ee58226..60a90a2617aea615849e0550efa7757e5296f0c5 100644 (file)
@@ -89,7 +89,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                return -EINVAL;
 
        if (buf->vb.size != size) {
-               saa7134_dma_free(dev,buf);
+               saa7134_dma_free(q,buf);
        }
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
@@ -98,7 +98,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                buf->vb.size   = size;
                buf->pt        = &dev->ts.pt_ts;
 
-               err = videobuf_iolock(dev->pci,&buf->vb,NULL);
+               err = videobuf_iolock(q,&buf->vb,NULL);
                if (err)
                        goto oops;
                err = saa7134_pgtable_build(dev->pci,buf->pt,
@@ -126,7 +126,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        return 0;
 
  oops:
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
        return err;
 }
 
@@ -152,10 +152,9 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
 }
 
 struct videobuf_queue_ops saa7134_ts_qops = {
index 3043233a8b6e2d7e0f70cb159061e9cead7295db..0db53d192b2a2b1d40f975b63256066982ba1e3e 100644 (file)
@@ -482,12 +482,14 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
                [ V4L2_TUNER_MODE_STEREO ] = "stereo",
                [ V4L2_TUNER_MODE_LANG1  ] = "lang1",
                [ V4L2_TUNER_MODE_LANG2  ] = "lang2",
+               [ V4L2_TUNER_MODE_LANG1_LANG2  ] = "lang1+lang2",
        };
        static u32 fm[] = {
                [ V4L2_TUNER_MODE_MONO   ] = 0x00,  /* ch1  */
                [ V4L2_TUNER_MODE_STEREO ] = 0x80,  /* auto */
                [ V4L2_TUNER_MODE_LANG1  ] = 0x00,  /* ch1  */
                [ V4L2_TUNER_MODE_LANG2  ] = 0x01,  /* ch2  */
+               [ V4L2_TUNER_MODE_LANG1_LANG2 ] = 0x80,  /* auto */
        };
        u32 reg;
 
index f4aee0af80e19a942e7d10e28b7321cae709c34c..f38366a470fa58c4cb677f3af1074054418710c8 100644 (file)
@@ -135,7 +135,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                return -EINVAL;
 
        if (buf->vb.size != size)
-               saa7134_dma_free(dev,buf);
+               saa7134_dma_free(q,buf);
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
                buf->vb.width  = llength;
@@ -143,7 +143,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                buf->vb.size   = size;
                buf->pt        = &fh->pt_vbi;
 
-               err = videobuf_iolock(dev->pci,&buf->vb,NULL);
+               err = videobuf_iolock(q,&buf->vb,NULL);
                if (err)
                        goto oops;
                err = saa7134_pgtable_build(dev->pci,buf->pt,
@@ -159,7 +159,7 @@ static int buffer_prepare(struct videobuf_queue *q,
        return 0;
 
  oops:
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
        return err;
 }
 
@@ -190,11 +190,9 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh   = q->priv_data;
-       struct saa7134_dev *dev = fh->dev;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
 }
 
 struct videobuf_queue_ops saa7134_vbi_qops = {
index 57a11e71d9969ec3b164c8fbf8876ee35fec85db..aeef80f88a6bb0076a1c7e23709b17b0f1420e09 100644 (file)
@@ -993,7 +993,7 @@ static int buffer_prepare(struct videobuf_queue *q,
            buf->vb.size   != size       ||
            buf->vb.field  != field      ||
            buf->fmt       != fh->fmt) {
-               saa7134_dma_free(dev,buf);
+               saa7134_dma_free(q,buf);
        }
 
        if (STATE_NEEDS_INIT == buf->vb.state) {
@@ -1004,7 +1004,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                buf->fmt       = fh->fmt;
                buf->pt        = &fh->pt_cap;
 
-               err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf);
+               err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
                if (err)
                        goto oops;
                err = saa7134_pgtable_build(dev->pci,buf->pt,
@@ -1019,7 +1019,7 @@ static int buffer_prepare(struct videobuf_queue *q,
        return 0;
 
  oops:
-       saa7134_dma_free(dev,buf);
+       saa7134_dma_free(q,buf);
        return err;
 }
 
@@ -1045,10 +1045,9 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 
-       saa7134_dma_free(fh->dev,buf);
+       saa7134_dma_free(q,buf);
 }
 
 static struct videobuf_queue_ops video_qops = {
index ce1c2e0b065ee84f1b1052a5c7fc14c19c049cbd..31ba293854c1951912dd81543e3ab72bd2d587ee 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/io.h>
 
 #include <media/tuner.h>
-#include <media/audiochip.h>
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/video-buf.h>
@@ -579,7 +578,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
                           unsigned int state);
 void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
 void saa7134_buffer_timeout(unsigned long data);
-void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf);
+void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
 
 int saa7134_set_dmabits(struct saa7134_dev *dev);
 
index 756963f01bbdcb7de9042793264f93cca88d719f..2830b5e33aec97c90b94acfd9756def5aa50d13c 100644 (file)
@@ -1,7 +1,7 @@
-/*  
+/*
     saa7146.h - definitions philips saa7146 based cards
     Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-    
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -27,7 +27,7 @@
 
 #include <linux/videodev.h>
 
-#ifndef O_NONCAP  
+#ifndef O_NONCAP
 #define O_NONCAP       O_TRUNC
 #endif
 
@@ -36,7 +36,7 @@
 
 #ifdef __KERNEL__
 
-struct saa7146_window 
+struct saa7146_window
 {
        int x, y;
        ushort width, height;
@@ -70,7 +70,7 @@ struct saa7146
        int irqstate;           /* irq routine is state driven */
        int writemode;
        int playmode;
-        unsigned int nr;
+       unsigned int nr;
        unsigned long irq;          /* IRQ used by SAA7146 card */
        unsigned short id;
        unsigned char revision;
index 6cc910f50a4bb20e53743bfd8bd84620712f7590..80ec2c146b4c6fef4a2b4868ae3771109b672736 100644 (file)
@@ -1,7 +1,7 @@
-/*  
+/*
     saa7146.h - definitions philips saa7146 based cards
     Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-    
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
index 9f99ee1303e0b8a47c3dd1504198960aec8d58e8..9c308410856d9ad211d89fd2907e96ffd1dfa2ab 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * saa7185 - Philips SAA7185B video encoder driver version 0.0.3
  *
  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
@@ -377,7 +377,7 @@ saa7185_command (struct i2c_client *client,
 static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
index f92f21cfbcac93ddfab41bb4e4434e377b2c27b9..cd4b6354a7b3c33112ae3aa62f91003eaf5c614d 100644 (file)
@@ -2,14 +2,14 @@
     Definitions for the Philips SAA7196 digital video decoder,
     scaler, and clock generator circuit (DESCpro), as used in
     the PlanB video input of the Powermac 7x00/8x00 series.
-  
+
     Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
 
     The register defines are shamelessly copied from the meteor
     driver out of NetBSD (with permission),
     and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe
     (Thanks !)
-  
+
     Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu)
 
     The default values used for PlanB are my mistakes.
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
new file mode 100644 (file)
index 0000000..a846ebc
--- /dev/null
@@ -0,0 +1,1435 @@
+/*
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
+ * their chipset available and supporting me while writing this driver.
+ *     - Jeroen Vreeken
+ */
+
+static const char version[] = "0.24";
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/usb.h>
+#include "se401.h"
+
+static int flickerless=0;
+static int video_nr = -1;
+
+static struct usb_device_id device_table [] = {
+       { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
+       { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
+       { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
+       { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
+       { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("SE401 USB Camera Driver");
+MODULE_LICENSE("GPL");
+module_param(flickerless, int, 0);
+MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+module_param(video_nr, int, 0);
+
+static struct usb_driver se401_driver;
+
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ **********************************************************************/
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+
+
+/****************************************************************************
+ *
+ * se401 register read/write functions
+ *
+ ***************************************************************************/
+
+static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
+                        unsigned short value, unsigned char *cp, int size)
+{
+       return usb_control_msg (
+               se401->dev,
+               set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
+               req,
+               (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               value,
+               0,
+               cp,
+               size,
+               1000
+       );
+}
+
+static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
+                            unsigned short param)
+{
+       /* specs say that the selector (address) should go in the value field
+          and the param in index, but in the logs of the windows driver they do
+          this the other way around...
+        */
+       return usb_control_msg (
+               se401->dev,
+               usb_sndctrlpipe(se401->dev, 0),
+               SE401_REQ_SET_EXT_FEATURE,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               param,
+               selector,
+               NULL,
+               0,
+               1000
+       );
+}
+
+static unsigned short se401_get_feature(struct usb_se401 *se401,
+                                       unsigned short selector)
+{
+       /* For 'set' the selecetor should be in index, not sure if the spec is
+          wrong here to....
+        */
+       unsigned char cp[2];
+       usb_control_msg (
+               se401->dev,
+               usb_rcvctrlpipe(se401->dev, 0),
+               SE401_REQ_GET_EXT_FEATURE,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               0,
+               selector,
+               cp,
+               2,
+               1000
+       );
+       return cp[0]+cp[1]*256;
+}
+
+/****************************************************************************
+ *
+ * Camera control
+ *
+ ***************************************************************************/
+
+
+static int se401_send_pict(struct usb_se401 *se401)
+{
+       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
+       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
+       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
+       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
+       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
+       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+
+       return 0;
+}
+
+static void se401_set_exposure(struct usb_se401 *se401, int brightness)
+{
+       int integration=brightness<<5;
+
+       if (flickerless==50) {
+               integration=integration-integration%106667;
+       }
+       if (flickerless==60) {
+               integration=integration-integration%88889;
+       }
+       se401->brightness=integration>>5;
+       se401->expose_h=(integration>>16)&0xff;
+       se401->expose_m=(integration>>8)&0xff;
+       se401->expose_l=integration&0xff;
+}
+
+static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+       p->brightness=se401->brightness;
+       if (se401->enhance) {
+               p->whiteness=32768;
+       } else {
+               p->whiteness=0;
+       }
+       p->colour=65535;
+       p->contrast=65535;
+       p->hue=se401->rgain<<10;
+       p->palette=se401->palette;
+       p->depth=3; /* rgb24 */
+       return 0;
+}
+
+
+static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+       if (p->palette != VIDEO_PALETTE_RGB24)
+               return 1;
+       se401->palette=p->palette;
+       if (p->hue!=se401->hue) {
+               se401->rgain= p->hue>>10;
+               se401->bgain= 0x40-(p->hue>>10);
+               se401->hue=p->hue;
+       }
+       if (p->brightness!=se401->brightness) {
+               se401_set_exposure(se401, p->brightness);
+       }
+       if (p->whiteness>=32768) {
+               se401->enhance=1;
+       } else {
+               se401->enhance=0;
+       }
+       se401_send_pict(se401);
+       se401_send_pict(se401);
+       return 0;
+}
+
+/*
+       Hyundai have some really nice docs about this and other sensor related
+       stuff on their homepage: www.hei.co.kr
+*/
+static void se401_auto_resetlevel(struct usb_se401 *se401)
+{
+       unsigned int ahrc, alrc;
+       int oldreset=se401->resetlevel;
+
+       /* For some reason this normally read-only register doesn't get reset
+          to zero after reading them just once...
+        */
+       se401_get_feature(se401, HV7131_REG_HIREFNOH);
+       se401_get_feature(se401, HV7131_REG_HIREFNOL);
+       se401_get_feature(se401, HV7131_REG_LOREFNOH);
+       se401_get_feature(se401, HV7131_REG_LOREFNOL);
+       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
+           se401_get_feature(se401, HV7131_REG_HIREFNOL);
+       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+           se401_get_feature(se401, HV7131_REG_LOREFNOL);
+
+       /* Not an exact science, but it seems to work pretty well... */
+       if (alrc > 10) {
+               while (alrc>=10 && se401->resetlevel < 63) {
+                       se401->resetlevel++;
+                       alrc /=2;
+               }
+       } else if (ahrc > 20) {
+               while (ahrc>=20 && se401->resetlevel > 0) {
+                       se401->resetlevel--;
+                       ahrc /=2;
+               }
+       }
+       if (se401->resetlevel!=oldreset)
+               se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+
+       return;
+}
+
+/* irq handler for snapshot button */
+static void se401_button_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_se401 *se401 = urb->context;
+       int status;
+
+       if (!se401->dev) {
+               info("ohoh: device vapourished");
+               return;
+       }
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       if (urb->actual_length >=2) {
+               if (se401->button)
+                       se401->buttonpressed=1;
+       }
+exit:
+       status = usb_submit_urb (urb, GFP_ATOMIC);
+       if (status)
+               err ("%s - usb_submit_urb failed with result %d",
+                    __FUNCTION__, status);
+}
+
+static void se401_video_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_se401 *se401 = urb->context;
+       int length = urb->actual_length;
+
+       /* ohoh... */
+       if (!se401->streaming)
+               return;
+
+       if (!se401->dev) {
+               info ("ohoh: device vapourished");
+               return;
+       }
+
+       /* 0 sized packets happen if we are to fast, but sometimes the camera
+          keeps sending them forever...
+        */
+       if (length && !urb->status) {
+               se401->nullpackets=0;
+               switch(se401->scratch[se401->scratch_next].state) {
+                       case BUFFER_READY:
+                       case BUFFER_BUSY: {
+                               se401->dropped++;
+                               break;
+                       }
+                       case BUFFER_UNUSED: {
+                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
+                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
+                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
+                               se401->scratch[se401->scratch_next].length=length;
+                               if (waitqueue_active(&se401->wq)) {
+                                       wake_up_interruptible(&se401->wq);
+                               }
+                               se401->scratch_overflow=0;
+                               se401->scratch_next++;
+                               if (se401->scratch_next>=SE401_NUMSCRATCH)
+                                       se401->scratch_next=0;
+                               break;
+                       }
+               }
+               se401->bayeroffset+=length;
+               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
+                       se401->bayeroffset=0;
+               }
+       } else {
+               se401->nullpackets++;
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+                       if (waitqueue_active(&se401->wq)) {
+                               wake_up_interruptible(&se401->wq);
+                       }
+               }
+       }
+
+       /* Resubmit urb for new data */
+       urb->status=0;
+       urb->dev=se401->dev;
+       if(usb_submit_urb(urb, GFP_KERNEL))
+               info("urb burned down");
+       return;
+}
+
+static void se401_send_size(struct usb_se401 *se401, int width, int height)
+{
+       int i=0;
+       int mode=0x03; /* No compression */
+       int sendheight=height;
+       int sendwidth=width;
+
+       /* JangGu compression can only be used with the camera supported sizes,
+          but bayer seems to work with any size that fits on the sensor.
+          We check if we can use compression with the current size with either
+          4 or 16 times subcapturing, if not we use uncompressed bayer data
+          but this will result in cutouts of the maximum size....
+        */
+       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+               i++;
+       while (i<se401->sizes) {
+               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
+                       sendheight=se401->height[i];
+                       sendwidth=se401->width[i];
+                       mode=0x40;
+               }
+               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
+                       sendheight=se401->height[i];
+                       sendwidth=se401->width[i];
+                       mode=0x42;
+               }
+               i++;
+       }
+
+       se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
+       se401_set_feature(se401, SE401_OPERATINGMODE, mode);
+
+       if (mode==0x03) {
+               se401->format=FMT_BAYER;
+       } else {
+               se401->format=FMT_JANGGU;
+       }
+
+       return;
+}
+
+/*
+       In this function se401_send_pict is called several times,
+       for some reason (depending on the state of the sensor and the phase of
+       the moon :) doing this only in either place doesn't always work...
+*/
+static int se401_start_stream(struct usb_se401 *se401)
+{
+       struct urb *urb;
+       int err=0, i;
+       se401->streaming=1;
+
+       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+       /* Set picture settings */
+       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+       se401_send_pict(se401);
+
+       se401_send_size(se401, se401->cwidth, se401->cheight);
+
+       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+       /* Do some memory allocation */
+       for (i=0; i<SE401_NUMFRAMES; i++) {
+               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
+               se401->frame[i].curpix=0;
+       }
+       for (i=0; i<SE401_NUMSBUF; i++) {
+               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       }
+
+       se401->bayeroffset=0;
+       se401->scratch_next=0;
+       se401->scratch_use=0;
+       se401->scratch_overflow=0;
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+               se401->scratch[i].state=BUFFER_UNUSED;
+       }
+
+       for (i=0; i<SE401_NUMSBUF; i++) {
+               urb=usb_alloc_urb(0, GFP_KERNEL);
+               if(!urb)
+                       return -ENOMEM;
+
+               usb_fill_bulk_urb(urb, se401->dev,
+                       usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
+                       se401->sbuf[i].data, SE401_PACKETSIZE,
+                       se401_video_irq,
+                       se401);
+
+               se401->urb[i]=urb;
+
+               err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
+               if(err)
+                       err("urb burned down");
+       }
+
+       se401->framecount=0;
+
+       return 0;
+}
+
+static int se401_stop_stream(struct usb_se401 *se401)
+{
+       int i;
+
+       if (!se401->streaming || !se401->dev)
+               return 1;
+
+       se401->streaming=0;
+
+       se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+
+       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+               usb_kill_urb(se401->urb[i]);
+               usb_free_urb(se401->urb[i]);
+               se401->urb[i]=NULL;
+               kfree(se401->sbuf[i].data);
+       }
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               kfree(se401->scratch[i].data);
+               se401->scratch[i].data=NULL;
+       }
+
+       return 0;
+}
+
+static int se401_set_size(struct usb_se401 *se401, int width, int height)
+{
+       int wasstreaming=se401->streaming;
+       /* Check to see if we need to change */
+       if (se401->cwidth==width && se401->cheight==height)
+               return 0;
+
+       /* Check for a valid mode */
+       if (!width || !height)
+               return 1;
+       if ((width & 1) || (height & 1))
+               return 1;
+       if (width>se401->width[se401->sizes-1])
+               return 1;
+       if (height>se401->height[se401->sizes-1])
+               return 1;
+
+       /* Stop a current stream and start it again at the new size */
+       if (wasstreaming)
+               se401_stop_stream(se401);
+       se401->cwidth=width;
+       se401->cheight=height;
+       if (wasstreaming)
+               se401_start_stream(se401);
+       return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video Decoding
+ *
+ ***************************************************************************/
+
+/*
+       This shouldn't really be done in a v4l driver....
+       But it does make the image look a lot more usable.
+       Basically it lifts the dark pixels more than the light pixels.
+*/
+static inline void enhance_picture(unsigned char *frame, int len)
+{
+       while (len--) {
+               *frame=(((*frame^255)*(*frame^255))/255)^255;
+               frame++;
+       }
+}
+
+static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
+{
+       struct se401_frame *frame=&se401->frame[se401->curframe];
+       int linelength=se401->cwidth*3;
+
+       if (frame->curlinepix >= linelength) {
+               frame->curlinepix=0;
+               frame->curline+=linelength;
+       }
+
+       /* First three are absolute, all others relative.
+        * Format is rgb from right to left (mirrorred image),
+        * we flip it to get bgr from left to right. */
+       if (frame->curlinepix < 3) {
+               *(frame->curline-frame->curlinepix)=1+data*4;
+       } else {
+               *(frame->curline-frame->curlinepix)=
+                   *(frame->curline-frame->curlinepix+3)+data*4;
+       }
+       frame->curlinepix++;
+}
+
+static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+{
+       int pos=0;
+       int vlc_cod=0;
+       int vlc_size=0;
+       int vlc_data=0;
+       int bit_cur;
+       int bit;
+       data+=4;
+       while (pos < packetlength) {
+               bit_cur=8;
+               while (bit_cur && bit_exp) {
+                       bit=((*data)>>(bit_cur-1))&1;
+                       if (!vlc_cod) {
+                               if (bit) {
+                                       vlc_size++;
+                               } else {
+                                       if (!vlc_size) {
+                                               decode_JangGu_integrate(se401, 0);
+                                       } else {
+                                               vlc_cod=2;
+                                               vlc_data=0;
+                                       }
+                               }
+                       } else {
+                               if (vlc_cod==2) {
+                                       if (!bit)
+                                               vlc_data =  -(1<<vlc_size) + 1;
+                                       vlc_cod--;
+                               }
+                               vlc_size--;
+                               vlc_data+=bit<<vlc_size;
+                               if (!vlc_size) {
+                                       decode_JangGu_integrate(se401, vlc_data);
+                                       vlc_cod=0;
+                               }
+                       }
+                       bit_cur--;
+                       bit_exp--;
+               }
+               pos++;
+               data++;
+       }
+}
+
+static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+       unsigned char *data=buffer->data;
+       int len=buffer->length;
+       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
+       int datapos=0;
+
+       /* New image? */
+       if (!se401->frame[se401->curframe].curpix) {
+               se401->frame[se401->curframe].curlinepix=0;
+               se401->frame[se401->curframe].curline=
+                   se401->frame[se401->curframe].data+
+                   se401->cwidth*3-1;
+               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
+                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
+               se401->vlcdatapos=0;
+       }
+       while (datapos < len) {
+               size=1024-se401->vlcdatapos;
+               if (size+datapos > len)
+                       size=len-datapos;
+               memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
+               se401->vlcdatapos+=size;
+               packetlength=0;
+               if (se401->vlcdatapos >= 4) {
+                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
+                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
+                       frameinfo=se401->vlcdata[0]&0xc0;
+                       packetlength=((bit_exp+47)>>4)<<1;
+                       if (packetlength > 1024) {
+                               se401->vlcdatapos=0;
+                               datapos=len;
+                               packetlength=0;
+                               se401->error++;
+                               se401->frame[se401->curframe].curpix=0;
+                       }
+               }
+               if (packetlength && se401->vlcdatapos >= packetlength) {
+                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
+                       se401->frame[se401->curframe].curpix+=pix_exp*3;
+                       datapos+=size-(se401->vlcdatapos-packetlength);
+                       se401->vlcdatapos=0;
+                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
+                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
+                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
+                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
+                                               se401->framecount++;
+                                               se401->readcount++;
+                                       }
+                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+                                       }
+                               } else {
+                                       se401->error++;
+                               }
+                               se401->frame[se401->curframe].curpix=0;
+                               datapos=len;
+                       }
+               } else {
+                       datapos+=size;
+               }
+       }
+}
+
+static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+       unsigned char *data=buffer->data;
+       int len=buffer->length;
+       int offset=buffer->offset;
+       int datasize=se401->cwidth*se401->cheight;
+       struct se401_frame *frame=&se401->frame[se401->curframe];
+
+       unsigned char *framedata=frame->data, *curline, *nextline;
+       int width=se401->cwidth;
+       int blineoffset=0, bline;
+       int linelength=width*3, i;
+
+
+       if (frame->curpix==0) {
+               if (frame->grabstate==FRAME_READY) {
+                       frame->grabstate=FRAME_GRABBING;
+               }
+               frame->curline=framedata+linelength;
+               frame->curlinepix=0;
+       }
+
+       if (offset!=frame->curpix) {
+               /* Regard frame as lost :( */
+               frame->curpix=0;
+               se401->error++;
+               return;
+       }
+
+       /* Check if we have to much data */
+       if (frame->curpix+len > datasize) {
+               len=datasize-frame->curpix;
+       }
+       if (se401->cheight%4)
+               blineoffset=1;
+       bline=frame->curpix/se401->cwidth+blineoffset;
+
+       curline=frame->curline;
+       nextline=curline+linelength;
+       if (nextline >= framedata+datasize*3)
+               nextline=curline;
+       while (len) {
+               if (frame->curlinepix>=width) {
+                       frame->curlinepix-=width;
+                       bline=frame->curpix/width+blineoffset;
+                       curline+=linelength*2;
+                       nextline+=linelength*2;
+                       if (curline >= framedata+datasize*3) {
+                               frame->curlinepix++;
+                               curline-=3;
+                               nextline-=3;
+                               len--;
+                               data++;
+                               frame->curpix++;
+                       }
+                       if (nextline >= framedata+datasize*3)
+                               nextline=curline;
+               }
+               if ((bline&1)) {
+                       if ((frame->curlinepix&1)) {
+                               *(curline+2)=*data;
+                               *(curline-1)=*data;
+                               *(nextline+2)=*data;
+                               *(nextline-1)=*data;
+                       } else {
+                               *(curline+1)=
+                                       (*(curline+1)+*data)/2;
+                               *(curline-2)=
+                                       (*(curline-2)+*data)/2;
+                               *(nextline+1)=*data;
+                               *(nextline-2)=*data;
+                       }
+               } else {
+                       if ((frame->curlinepix&1)) {
+                               *(curline+1)=
+                                       (*(curline+1)+*data)/2;
+                               *(curline-2)=
+                                       (*(curline-2)+*data)/2;
+                               *(nextline+1)=*data;
+                               *(nextline-2)=*data;
+                       } else {
+                               *curline=*data;
+                               *(curline-3)=*data;
+                               *nextline=*data;
+                               *(nextline-3)=*data;
+                       }
+               }
+               frame->curlinepix++;
+               curline-=3;
+               nextline-=3;
+               len--;
+               data++;
+               frame->curpix++;
+       }
+       frame->curline=curline;
+
+       if (frame->curpix>=datasize) {
+               /* Fix the top line */
+               framedata+=linelength;
+               for (i=0; i<linelength; i++) {
+                       framedata--;
+                       *framedata=*(framedata+linelength);
+               }
+               /* Fix the left side (green is already present) */
+               for (i=0; i<se401->cheight; i++) {
+                       *framedata=*(framedata+3);
+                       *(framedata+1)=*(framedata+4);
+                       *(framedata+2)=*(framedata+5);
+                       framedata+=linelength;
+               }
+               frame->curpix=0;
+               frame->grabstate=FRAME_DONE;
+               se401->framecount++;
+               se401->readcount++;
+               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+               }
+       }
+}
+
+static int se401_newframe(struct usb_se401 *se401, int framenr)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int errors=0;
+
+       while (se401->streaming &&
+           (se401->frame[framenr].grabstate==FRAME_READY ||
+            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
+               if(!se401->frame[framenr].curpix) {
+                       errors++;
+               }
+               wait_interruptible(
+                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
+                   &se401->wq,
+                   &wait
+               );
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+                       se401->nullpackets=0;
+                       info("to many null length packets, restarting capture");
+                       se401_stop_stream(se401);
+                       se401_start_stream(se401);
+               } else {
+                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
+                               se401->frame[framenr].grabstate=FRAME_ERROR;
+                               return -EIO;
+                       }
+                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
+                       if (se401->format==FMT_JANGGU) {
+                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
+                       } else {
+                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
+                       }
+                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+                       se401->scratch_use++;
+                       if (se401->scratch_use>=SE401_NUMSCRATCH)
+                               se401->scratch_use=0;
+                       if (errors > SE401_MAX_ERRORS) {
+                               errors=0;
+                               info("to much errors, restarting capture");
+                               se401_stop_stream(se401);
+                               se401_start_stream(se401);
+                       }
+               }
+       }
+
+       if (se401->frame[framenr].grabstate==FRAME_DONE)
+               if (se401->enhance)
+                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+       return 0;
+}
+
+static void usb_se401_remove_disconnected (struct usb_se401 *se401)
+{
+       int i;
+
+       se401->dev = NULL;
+
+       for (i=0; i<SE401_NUMSBUF; i++)
+               if (se401->urb[i]) {
+                       usb_kill_urb(se401->urb[i]);
+                       usb_free_urb(se401->urb[i]);
+                       se401->urb[i] = NULL;
+                       kfree(se401->sbuf[i].data);
+               }
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               kfree(se401->scratch[i].data);
+       }
+       if (se401->inturb) {
+               usb_kill_urb(se401->inturb);
+               usb_free_urb(se401->inturb);
+       }
+       info("%s disconnected", se401->camera_name);
+
+       /* Free the memory */
+       kfree(se401->width);
+       kfree(se401->height);
+       kfree(se401);
+}
+
+
+
+/****************************************************************************
+ *
+ * Video4Linux
+ *
+ ***************************************************************************/
+
+
+static int se401_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       int err = 0;
+
+       if (se401->user)
+               return -EBUSY;
+       se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
+       if (se401->fbuf)
+               file->private_data = dev;
+       else
+               err = -ENOMEM;
+       se401->user = !err;
+
+       return err;
+}
+
+static int se401_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       int i;
+
+       rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
+       if (se401->removed) {
+               usb_se401_remove_disconnected(se401);
+               info("device unregistered");
+       } else {
+               for (i=0; i<SE401_NUMFRAMES; i++)
+                       se401->frame[i].grabstate=FRAME_UNUSED;
+               if (se401->streaming)
+                       se401_stop_stream(se401);
+               se401->user=0;
+       }
+       file->private_data = NULL;
+       return 0;
+}
+
+static int se401_do_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_se401 *se401 = (struct usb_se401 *)vdev;
+
+       if (!se401->dev)
+               return -EIO;
+
+       switch (cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability *b = arg;
+               strcpy(b->name, se401->camera_name);
+               b->type = VID_TYPE_CAPTURE;
+               b->channels = 1;
+               b->audios = 0;
+               b->maxwidth = se401->width[se401->sizes-1];
+               b->maxheight = se401->height[se401->sizes-1];
+               b->minwidth = se401->width[0];
+               b->minheight = se401->height[0];
+               return 0;
+       }
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *v = arg;
+
+               if (v->channel != 0)
+                       return -EINVAL;
+               v->flags = 0;
+               v->tuners = 0;
+               v->type = VIDEO_TYPE_CAMERA;
+               strcpy(v->name, "Camera");
+               return 0;
+       }
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *v = arg;
+
+               if (v->channel != 0)
+                       return -EINVAL;
+               return 0;
+       }
+       case VIDIOCGPICT:
+       {
+               struct video_picture *p = arg;
+
+               se401_get_pict(se401, p);
+               return 0;
+       }
+       case VIDIOCSPICT:
+       {
+               struct video_picture *p = arg;
+
+               if (se401_set_pict(se401, p))
+                       return -EINVAL;
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window *vw = arg;
+
+               if (vw->flags)
+                       return -EINVAL;
+               if (vw->clipcount)
+                       return -EINVAL;
+               if (se401_set_size(se401, vw->width, vw->height))
+                       return -EINVAL;
+               return 0;
+       }
+       case VIDIOCGWIN:
+       {
+               struct video_window *vw = arg;
+
+               vw->x = 0;               /* FIXME */
+               vw->y = 0;
+               vw->chromakey = 0;
+               vw->flags = 0;
+               vw->clipcount = 0;
+               vw->width = se401->cwidth;
+               vw->height = se401->cheight;
+               return 0;
+       }
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *vm = arg;
+               int i;
+
+               memset(vm, 0, sizeof(*vm));
+               vm->size = SE401_NUMFRAMES * se401->maxframesize;
+               vm->frames = SE401_NUMFRAMES;
+               for (i=0; i<SE401_NUMFRAMES; i++)
+                       vm->offsets[i] = se401->maxframesize * i;
+               return 0;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *vm = arg;
+
+               if (vm->format != VIDEO_PALETTE_RGB24)
+                       return -EINVAL;
+               if (vm->frame >= SE401_NUMFRAMES)
+                       return -EINVAL;
+               if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
+                       return -EBUSY;
+
+               /* Is this according to the v4l spec??? */
+               if (se401_set_size(se401, vm->width, vm->height))
+                       return -EINVAL;
+               se401->frame[vm->frame].grabstate=FRAME_READY;
+
+               if (!se401->streaming)
+                       se401_start_stream(se401);
+
+               /* Set the picture properties */
+               if (se401->framecount==0)
+                       se401_send_pict(se401);
+               /* Calibrate the reset level after a few frames. */
+               if (se401->framecount%20==1)
+                       se401_auto_resetlevel(se401);
+
+               return 0;
+       }
+       case VIDIOCSYNC:
+       {
+               int *frame = arg;
+               int ret=0;
+
+               if(*frame <0 || *frame >= SE401_NUMFRAMES)
+                       return -EINVAL;
+
+               ret=se401_newframe(se401, *frame);
+               se401->frame[*frame].grabstate=FRAME_UNUSED;
+               return ret;
+       }
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer *vb = arg;
+
+               memset(vb, 0, sizeof(*vb));
+               return 0;
+       }
+       case VIDIOCKEY:
+               return 0;
+       case VIDIOCCAPTURE:
+               return -EINVAL;
+       case VIDIOCSFBUF:
+               return -EINVAL;
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+               return -EINVAL;
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+               return -EINVAL;
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return -EINVAL;
+       default:
+               return -ENOIOCTLCMD;
+       } /* end switch */
+
+       return 0;
+}
+
+static int se401_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);
+}
+
+static ssize_t se401_read(struct file *file, char __user *buf,
+                    size_t count, loff_t *ppos)
+{
+       int realcount=count, ret=0;
+       struct video_device *dev = file->private_data;
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+
+
+       if (se401->dev == NULL)
+               return -EIO;
+       if (realcount > se401->cwidth*se401->cheight*3)
+               realcount=se401->cwidth*se401->cheight*3;
+
+       /* Shouldn't happen: */
+       if (se401->frame[0].grabstate==FRAME_GRABBING)
+               return -EBUSY;
+       se401->frame[0].grabstate=FRAME_READY;
+       se401->frame[1].grabstate=FRAME_UNUSED;
+       se401->curframe=0;
+
+       if (!se401->streaming)
+               se401_start_stream(se401);
+
+       /* Set the picture properties */
+       if (se401->framecount==0)
+               se401_send_pict(se401);
+       /* Calibrate the reset level after a few frames. */
+       if (se401->framecount%20==1)
+               se401_auto_resetlevel(se401);
+
+       ret=se401_newframe(se401, 0);
+
+       se401->frame[0].grabstate=FRAME_UNUSED;
+       if (ret)
+               return ret;
+       if (copy_to_user(buf, se401->frame[0].data, realcount))
+               return -EFAULT;
+
+       return realcount;
+}
+
+static int se401_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       mutex_lock(&se401->lock);
+
+       if (se401->dev == NULL) {
+               mutex_unlock(&se401->lock);
+               return -EIO;
+       }
+       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+               mutex_unlock(&se401->lock);
+               return -EINVAL;
+       }
+       pos = (unsigned long)se401->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       mutex_unlock(&se401->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       mutex_unlock(&se401->lock);
+
+       return 0;
+}
+
+static struct file_operations se401_fops = {
+       .owner =        THIS_MODULE,
+       .open =         se401_open,
+       .release =      se401_close,
+       .read =         se401_read,
+       .mmap =         se401_mmap,
+       .ioctl =        se401_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+static struct video_device se401_template = {
+       .owner =        THIS_MODULE,
+       .name =         "se401 USB camera",
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_SE401,
+       .fops =         &se401_fops,
+};
+
+
+
+/***************************/
+static int se401_init(struct usb_se401 *se401, int button)
+{
+       int i=0, rc;
+       unsigned char cp[0x40];
+       char temp[200];
+
+       /* led on */
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+       /* get camera descriptor */
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
+       if (cp[1]!=0x41) {
+               err("Wrong descriptor type");
+               return 1;
+       }
+       sprintf (temp, "ExtraFeatures: %d", cp[3]);
+
+       se401->sizes=cp[4]+cp[5]*256;
+       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       if (!se401->width)
+               return 1;
+       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       if (!se401->height) {
+               kfree(se401->width);
+               return 1;
+       }
+       for (i=0; i<se401->sizes; i++) {
+                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
+                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+       }
+       sprintf (temp, "%s Sizes:", temp);
+       for (i=0; i<se401->sizes; i++) {
+               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+       }
+       info("%s", temp);
+       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+       se401->cwidth=cp[0]+cp[1]*256;
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+       se401->cheight=cp[0]+cp[1]*256;
+
+       if (!cp[2] && SE401_FORMAT_BAYER) {
+               err("Bayer format not supported!");
+               return 1;
+       }
+       /* set output mode (BAYER) */
+       se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+       se401->brightness=cp[0]+cp[1]*256;
+       /* some default values */
+       se401->resetlevel=0x2d;
+       se401->rgain=0x20;
+       se401->ggain=0x20;
+       se401->bgain=0x20;
+       se401_set_exposure(se401, 20000);
+       se401->palette=VIDEO_PALETTE_RGB24;
+       se401->enhance=1;
+       se401->dropped=0;
+       se401->error=0;
+       se401->framecount=0;
+       se401->readcount=0;
+
+       /* Start interrupt transfers for snapshot button */
+       if (button) {
+               se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
+               if (!se401->inturb) {
+                       info("Allocation of inturb failed");
+                       return 1;
+               }
+               usb_fill_int_urb(se401->inturb, se401->dev,
+                   usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
+                   &se401->button, sizeof(se401->button),
+                   se401_button_irq,
+                   se401,
+                   8
+               );
+               if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
+                       info("int urb burned down");
+                       return 1;
+               }
+       } else
+               se401->inturb=NULL;
+
+       /* Flash the led */
+       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+
+       return 0;
+}
+
+static int se401_probe(struct usb_interface *intf,
+       const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_interface_descriptor *interface;
+       struct usb_se401 *se401;
+       char *camera_name=NULL;
+       int button=1;
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       interface = &intf->cur_altsetting->desc;
+
+       /* Is it an se401? */
+       if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
+               camera_name="Endpoints/Aox SE401";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
+               camera_name="Philips PCVC665K";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
+               camera_name="Kensington VideoCAM 67014";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
+               camera_name="Kensington VideoCAM 6701(5/7)";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
+               camera_name="Kensington VideoCAM 67016";
+               button=0;
+       } else
+               return -ENODEV;
+
+       /* Checking vendor/product should be enough, but what the hell */
+       if (interface->bInterfaceClass != 0x00)
+               return -ENODEV;
+       if (interface->bInterfaceSubClass != 0x00)
+               return -ENODEV;
+
+       /* We found one */
+       info("SE401 camera found: %s", camera_name);
+
+       if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+               err("couldn't kmalloc se401 struct");
+               return -ENOMEM;
+       }
+
+       se401->dev = dev;
+       se401->iface = interface->bInterfaceNumber;
+       se401->camera_name = camera_name;
+
+       info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
+
+       if (se401_init(se401, button)) {
+               kfree(se401);
+               return -EIO;
+       }
+
+       memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
+       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+       init_waitqueue_head(&se401->wq);
+       mutex_init(&se401->lock);
+       wmb();
+
+       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               kfree(se401);
+               err("video_register_device failed");
+               return -EIO;
+       }
+       info("registered new video device: video%d", se401->vdev.minor);
+
+       usb_set_intfdata (intf, se401);
+       return 0;
+}
+
+static void se401_disconnect(struct usb_interface *intf)
+{
+       struct usb_se401 *se401 = usb_get_intfdata (intf);
+
+       usb_set_intfdata (intf, NULL);
+       if (se401) {
+               video_unregister_device(&se401->vdev);
+               if (!se401->user){
+                       usb_se401_remove_disconnected(se401);
+               } else {
+                       se401->frame[0].grabstate = FRAME_ERROR;
+                       se401->frame[0].grabstate = FRAME_ERROR;
+
+                       se401->streaming = 0;
+
+                       wake_up_interruptible(&se401->wq);
+                       se401->removed = 1;
+               }
+       }
+}
+
+static struct usb_driver se401_driver = {
+       .name           = "se401",
+       .id_table       = device_table,
+       .probe          = se401_probe,
+       .disconnect     = se401_disconnect,
+};
+
+
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init usb_se401_init(void)
+{
+       info("SE401 usb camera driver version %s registering", version);
+       if (flickerless)
+               if (flickerless!=50 && flickerless!=60) {
+                       info("Invallid flickerless value, use 0, 50 or 60.");
+                       return -1;
+       }
+       return usb_register(&se401_driver);
+}
+
+static void __exit usb_se401_exit(void)
+{
+       usb_deregister(&se401_driver);
+       info("SE401 driver deregistered");
+}
+
+module_init(usb_se401_init);
+module_exit(usb_se401_exit);
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
new file mode 100644 (file)
index 0000000..a7a216b
--- /dev/null
@@ -0,0 +1,234 @@
+
+#ifndef __LINUX_se401_H
+#define __LINUX_se401_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+
+#define se401_DEBUG    /* Turn on debug messages */
+
+#ifdef se401_DEBUG
+#  define PDEBUG(level, fmt, args...) \
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+#else
+#  define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* An almost drop-in replacement for sleep_on_interruptible */
+#define wait_interruptible(test, queue, wait) \
+{ \
+       add_wait_queue(queue, wait); \
+       set_current_state(TASK_INTERRUPTIBLE); \
+       if (test) \
+               schedule(); \
+       remove_wait_queue(queue, wait); \
+       set_current_state(TASK_RUNNING); \
+       if (signal_pending(current)) \
+               break; \
+}
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
+#define SE401_REQ_CAPTURE_FRAME                        0x43
+#define SE401_REQ_GET_BRT                      0x44
+#define SE401_REQ_SET_BRT                      0x45
+#define SE401_REQ_GET_WIDTH                    0x4c
+#define SE401_REQ_SET_WIDTH                    0x4d
+#define SE401_REQ_GET_HEIGHT                   0x4e
+#define SE401_REQ_SET_HEIGHT                   0x4f
+#define SE401_REQ_GET_OUTPUT_MODE              0x50
+#define SE401_REQ_SET_OUTPUT_MODE              0x51
+#define SE401_REQ_GET_EXT_FEATURE              0x52
+#define SE401_REQ_SET_EXT_FEATURE              0x53
+#define SE401_REQ_CAMERA_POWER                 0x56
+#define SE401_REQ_LED_CONTROL                  0x57
+#define SE401_REQ_BIOS                         0xff
+
+#define SE401_BIOS_READ                                0x07
+
+#define SE401_FORMAT_BAYER     0x40
+
+/* Hyundai hv7131b registers
+   7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A              0x00
+#define HV7131_REG_MODE_B              0x01
+#define HV7131_REG_MODE_C              0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU                0x10
+#define HV7131_REG_FRSL                0x11
+#define HV7131_REG_FCSU                0x12
+#define HV7131_REG_FCSL                0x13
+#define HV7131_REG_FWHU                0x14
+#define HV7131_REG_FWHL                0x15
+#define HV7131_REG_FWWU                0x16
+#define HV7131_REG_FWWL                0x17
+/* Timing registers: */
+#define HV7131_REG_THBU                0x20
+#define HV7131_REG_THBL                0x21
+#define HV7131_REG_TVBU                0x22
+#define HV7131_REG_TVBL                0x23
+#define HV7131_REG_TITU                0x25
+#define HV7131_REG_TITM                0x26
+#define HV7131_REG_TITL                0x27
+#define HV7131_REG_TMCD                0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV                0x30
+#define HV7131_REG_ARCG                0x31
+#define HV7131_REG_AGCG                0x32
+#define HV7131_REG_ABCG                0x33
+#define HV7131_REG_APBV                0x34
+#define HV7131_REG_ASLP                0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR                0x50
+#define HV7131_REG_OFSG                0x51
+#define HV7131_REG_OFSB                0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH    0x57
+#define HV7131_REG_LOREFNOL    0x58
+#define HV7131_REG_HIREFNOH    0x59
+#define HV7131_REG_HIREFNOL    0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE    0x2000
+
+
+/* size of usb transfers */
+#define SE401_PACKETSIZE       4096
+/* number of queued bulk transfers to use, should be about 8 */
+#define SE401_NUMSBUF          1
+/* read the usb specs for this one :) */
+#define SE401_VIDEO_ENDPOINT   1
+#define SE401_BUTTON_ENDPOINT  2
+/* number of frames supported by the v4l part */
+#define SE401_NUMFRAMES                2
+/* scratch buffers for passing data to the decoders */
+#define SE401_NUMSCRATCH       32
+/* maximum amount of data in a JangGu packet */
+#define SE401_VLCDATALEN       1024
+/* number of nul sized packets to receive before kicking the camera */
+#define SE401_MAX_NULLPACKETS  4000
+/* number of decoding errors before kicking the camera */
+#define SE401_MAX_ERRORS       200
+
+struct usb_device;
+
+struct se401_sbuf {
+       unsigned char *data;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+enum {
+       FMT_BAYER,
+       FMT_JANGGU,
+};
+
+enum {
+       BUFFER_UNUSED,
+       BUFFER_READY,
+       BUFFER_BUSY,
+       BUFFER_DONE,
+};
+
+struct se401_scratch {
+       unsigned char *data;
+       volatile int state;
+       int offset;
+       int length;
+};
+
+struct se401_frame {
+       unsigned char *data;            /* Frame buffer */
+
+       volatile int grabstate; /* State of grabbing */
+
+       unsigned char *curline;
+       int curlinepix;
+       int curpix;
+};
+
+struct usb_se401 {
+       struct video_device vdev;
+
+       /* Device structure */
+       struct usb_device *dev;
+
+       unsigned char iface;
+
+       char *camera_name;
+
+       int change;
+       int brightness;
+       int hue;
+       int rgain;
+       int ggain;
+       int bgain;
+       int expose_h;
+       int expose_m;
+       int expose_l;
+       int resetlevel;
+
+       int enhance;
+
+       int format;
+       int sizes;
+       int *width;
+       int *height;
+       int cwidth;             /* current width */
+       int cheight;            /* current height */
+       int palette;
+       int maxframesize;
+       int cframesize;         /* current framesize */
+
+       struct mutex lock;
+       int user;               /* user count for exclusive use */
+       int removed;            /* device disconnected */
+
+       int streaming;          /* Are we streaming video? */
+
+       char *fbuf;             /* Videodev buffer area */
+
+       struct urb *urb[SE401_NUMSBUF];
+       struct urb *inturb;
+
+       int button;
+       int buttonpressed;
+
+       int curframe;           /* Current receiving frame */
+       struct se401_frame frame[SE401_NUMFRAMES];
+       int readcount;
+       int framecount;
+       int error;
+       int dropped;
+
+       int scratch_next;
+       int scratch_use;
+       int scratch_overflow;
+       struct se401_scratch scratch[SE401_NUMSCRATCH];
+
+       /* Decoder specific data: */
+       unsigned char vlcdata[SE401_VLCDATALEN];
+       int vlcdatapos;
+       int bayeroffset;
+
+       struct se401_sbuf sbuf[SE401_NUMSBUF];
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int nullpackets;
+};
+
+
+
+#endif
+
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
new file mode 100644 (file)
index 0000000..536ad30
--- /dev/null
@@ -0,0 +1,7 @@
+sn9c102-objs    := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
+                  sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+                  sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
+                  sn9c102_tas5130d1b.o
+
+obj-$(CONFIG_USB_SN9C102)       += sn9c102.o
+
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
new file mode 100644 (file)
index 0000000..2c6ff39
--- /dev/null
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _SN9C102_H_
+#define _SN9C102_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
+
+#include "sn9c102_sensor.h"
+
+/*****************************************************************************/
+
+#define SN9C102_DEBUG
+#define SN9C102_DEBUG_LEVEL       2
+#define SN9C102_MAX_DEVICES       64
+#define SN9C102_PRESERVE_IMGSCALE 0
+#define SN9C102_FORCE_MUNMAP      0
+#define SN9C102_MAX_FRAMES        32
+#define SN9C102_URBS              2
+#define SN9C102_ISO_PACKETS       7
+#define SN9C102_ALTERNATE_SETTING 8
+#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
+#define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     2
+
+/*****************************************************************************/
+
+enum sn9c102_bridge {
+       BRIDGE_SN9C101 = 0x01,
+       BRIDGE_SN9C102 = 0x02,
+       BRIDGE_SN9C103 = 0x04,
+};
+
+SN9C102_ID_TABLE
+SN9C102_SENSOR_TABLE
+
+enum sn9c102_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct sn9c102_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum sn9c102_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum sn9c102_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum sn9c102_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum sn9c102_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+typedef char sn9c103_sof_header_t[18];
+typedef char sn9c102_sof_header_t[12];
+typedef char sn9c102_eof_header_t[4];
+
+struct sn9c102_sysfs_attr {
+       u8 reg, i2c_reg;
+       sn9c103_sof_header_t frame_header;
+};
+
+struct sn9c102_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DEFINE_MUTEX(sn9c102_sysfs_lock);
+static DECLARE_RWSEM(sn9c102_disconnect);
+
+struct sn9c102_device {
+       struct video_device* v4ldev;
+
+       enum sn9c102_bridge bridge;
+       struct sn9c102_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[SN9C102_URBS];
+       void* transfer_buffer[SN9C102_URBS];
+       u8* control_buffer;
+
+       struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum sn9c102_io_method io;
+       enum sn9c102_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct sn9c102_sysfs_attr sysfs;
+       sn9c103_sof_header_t sof_header;
+       u16 reg[63];
+
+       struct sn9c102_module_param module_param;
+
+       enum sn9c102_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
+{
+       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+               return cam;
+
+       return NULL;
+}
+
+
+void
+sn9c102_attach_sensor(struct sn9c102_device* cam,
+                     struct sn9c102_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef SN9C102_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("sn9c102: " fmt "\n", ## args);               \
+               else if ((level) == 3)                                        \
+                       pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+        __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _SN9C102_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
new file mode 100644 (file)
index 0000000..ea4394d
--- /dev/null
@@ -0,0 +1,2919 @@
+/***************************************************************************
+ * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "sn9c102.h"
+
+/*****************************************************************************/
+
+#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
+#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
+#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
+#define SN9C102_MODULE_LICENSE  "GPL"
+#define SN9C102_MODULE_VERSION  "1:1.27"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
+
+MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
+MODULE_VERSION(SN9C102_MODULE_VERSION);
+MODULE_LICENSE(SN9C102_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                "\n -1 = use next available (default)"
+                "\n  n = use minor number n (integer >= 0)"
+                "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
+                " cameras this way."
+                "\nFor example:"
+                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                "\nthe second camera and use auto for the first"
+                "\none and for every other camera."
+                "\n");
+
+static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                              SN9C102_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                "\n<0|1[,...]> Force the application to unmap previously"
+                "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                "\nthis feature. This parameter is specific for each"
+                "\ndetected camera."
+                "\n 0 = do not force memory unmapping"
+                "\n 1 = force memory unmapping (save memory)"
+                "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                "\n");
+
+static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                                      SN9C102_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                "\n<n[,...]> Timeout for a video frame in seconds."
+                "\nThis parameter is specific for each detected camera."
+                "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
+                "\n");
+
+#ifdef SN9C102_DEBUG
+static unsigned short debug = SN9C102_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                "\n<n> Debugging information level, from 0 to 3:"
+                "\n0 = none (use carefully)"
+                "\n1 = critical errors"
+                "\n2 = significant informations"
+                "\n3 = more verbose messages"
+                "\nLevel 3 is useful for testing only, when only "
+                "one device is used."
+                "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
+                "\n");
+#endif
+
+/*****************************************************************************/
+
+static sn9c102_sof_header_t sn9c102_sof_header[] = {
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
+};
+
+static sn9c103_sof_header_t sn9c103_sof_header[] = {
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
+};
+
+static sn9c102_eof_header_t sn9c102_eof_header[] = {
+       {0x00, 0x00, 0x00, 0x00},
+       {0x40, 0x00, 0x00, 0x00},
+       {0x80, 0x00, 0x00, 0x00},
+       {0xc0, 0x00, 0x00, 0x00},
+};
+
+/*****************************************************************************/
+
+static u32
+sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
+                       enum sn9c102_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > SN9C102_MAX_FRAMES)
+               count = SN9C102_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void sn9c102_release_buffers(struct sn9c102_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
+{
+       struct sn9c102_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       int i, res;
+
+       if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             index, 0, buff, sizeof(buff),
+                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
+       if (res < 0) {
+               DBG(3, "Failed to write registers (index 0x%02X, error %d)",
+                   index, res);
+               return -1;
+       }
+
+       for (i = 0; i < sizeof(buff); i++)
+               cam->reg[index+i] = buff[i];
+
+       return 0;
+}
+
+
+int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       if (index >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       *buff = value;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (value 0x%02X, index "
+                      "0x%02X, error %d)", value, index, res);
+               return -1;
+       }
+
+       cam->reg[index] = value;
+
+       return 0;
+}
+
+
+/* NOTE: reading some registers always returns 0 */
+static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
+                   index, res);
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
+{
+       if (index >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       return cam->reg[index];
+}
+
+
+static int
+sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
+{
+       int i, r;
+
+       for (i = 1; i <= 5; i++) {
+               r = sn9c102_read_reg(cam, 0x08);
+               if (r < 0)
+                       return -EIO;
+               if (r & 0x04)
+                       return 0;
+               if (sensor->frequency & SN9C102_I2C_400KHZ)
+                       udelay(5*16);
+               else
+                       udelay(16*16);
+       }
+       return -EBUSY;
+}
+
+
+static int
+sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
+                             struct sn9c102_sensor* sensor)
+{
+       int r;
+       r = sn9c102_read_reg(cam, 0x08);
+       return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
+}
+
+
+static int
+sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
+                              struct sn9c102_sensor* sensor)
+{
+       int r;
+       r = sn9c102_read_reg(cam, 0x08);
+       return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
+}
+
+
+int
+sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
+                        struct sn9c102_sensor* sensor, u8 data0, u8 data1,
+                        u8 n, u8 buffer[])
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       /* Write cycle */
+       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
+       data[1] = data0; /* I2C slave id */
+       data[2] = data1; /* address */
+       data[7] = 0x10;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_wait(cam, sensor);
+
+       /* Read cycle - n bytes */
+       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
+                 (n << 4) | 0x02;
+       data[1] = data0;
+       data[7] = 0x10;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_wait(cam, sensor);
+
+       /* The first read byte will be placed in data[4] */
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_detect_read_error(cam, sensor);
+
+       PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
+             data[4]);
+
+       if (err) {
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
+               return -1;
+       }
+
+       if (buffer)
+               memcpy(buffer, data, sizeof(buffer));
+
+       return (int)data[4];
+}
+
+
+int
+sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
+                         struct sn9c102_sensor* sensor, u8 n, u8 data0,
+                         u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       /* Write cycle. It usually is address + value */
+       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
+                 | ((n - 1) << 4);
+       data[1] = data0;
+       data[2] = data1;
+       data[3] = data2;
+       data[4] = data3;
+       data[5] = data4;
+       data[6] = data5;
+       data[7] = 0x14;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_wait(cam, sensor);
+       err += sn9c102_i2c_detect_write_error(cam, sensor);
+
+       if (err)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
+             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
+             n, data0, data1, data2, data3, data4, data5);
+
+       return err ? -1 : 0;
+}
+
+
+int
+sn9c102_i2c_try_read(struct sn9c102_device* cam,
+                    struct sn9c102_sensor* sensor, u8 address)
+{
+       return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
+                                       address, 1, NULL);
+}
+
+
+int
+sn9c102_i2c_try_write(struct sn9c102_device* cam,
+                     struct sn9c102_sensor* sensor, u8 address, u8 value)
+{
+       return sn9c102_i2c_try_raw_write(cam, sensor, 3,
+                                        sensor->i2c_slave_id, address,
+                                        value, 0, 0, 0);
+}
+
+
+int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
+{
+       return sn9c102_i2c_try_read(cam, &cam->sensor, address);
+}
+
+
+int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
+{
+       return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
+}
+
+/*****************************************************************************/
+
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+       size_t soflen = 0, i;
+       u8 j, n = 0;
+
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               soflen = sizeof(sn9c102_sof_header_t);
+               n = sizeof(sn9c102_sof_header) / soflen;
+               break;
+       case BRIDGE_SN9C103:
+               soflen = sizeof(sn9c103_sof_header_t);
+               n = sizeof(sn9c103_sof_header) / soflen;
+       }
+
+       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
+               for (j = 0; j < n; j++)
+                       /* The invariable part of the header is 6 bytes long */
+                       if ((cam->bridge != BRIDGE_SN9C103 &&
+                           !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
+                           (cam->bridge == BRIDGE_SN9C103 &&
+                           !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
+                               memcpy(cam->sof_header, mem + i, soflen);
+                               /* Skip the header */
+                               return mem + i + soflen;
+                       }
+
+       return NULL;
+}
+
+
+static void*
+sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+       size_t eoflen = sizeof(sn9c102_eof_header_t), i;
+       unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
+
+       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+               return NULL; /* EOF header does not exist in compressed data */
+
+       for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
+               for (j = 0; j < n; j++)
+                       if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
+                               return mem + i;
+
+       return NULL;
+}
+
+
+static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct sn9c102_device* cam = urb->context;
+       struct sn9c102_frame_t** f;
+       size_t imagesize, soflen;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       soflen = (cam->bridge) == BRIDGE_SN9C103 ?
+                                 sizeof(sn9c103_sof_header_t) :
+                                 sizeof(sn9c102_sof_header_t);
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int img, len, status;
+               void *pos, *sof, *eof;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               PDBGG("Isochrnous frame: length %u, #%u i", len, i);
+
+redo:
+               sof = sn9c102_find_sof_header(cam, pos, len);
+               if (likely(!sof)) {
+                       eof = sn9c102_find_eof_header(cam, pos, len);
+                       if ((*f)->state == F_GRABBING) {
+end_of_frame:
+                               img = len;
+
+                               if (eof)
+                                       img = (eof > pos) ? eof - pos - 1 : 0;
+
+                               if ((*f)->buf.bytesused+img > imagesize) {
+                                       u32 b;
+                                       b = (*f)->buf.bytesused + img -
+                                           imagesize;
+                                       img = imagesize - (*f)->buf.bytesused;
+                                       DBG(3, "Expected EOF not found: "
+                                              "video frame cut");
+                                       if (eof)
+                                               DBG(3, "Exceeded limit: +%u "
+                                                      "bytes", (unsigned)(b));
+                               }
+
+                               memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
+                                      img);
+
+                               if ((*f)->buf.bytesused == 0)
+                                       do_gettimeofday(&(*f)->buf.timestamp);
+
+                               (*f)->buf.bytesused += img;
+
+                               if ((*f)->buf.bytesused == imagesize ||
+                                   (cam->sensor.pix_format.pixelformat ==
+                                               V4L2_PIX_FMT_SN9C10X && eof)) {
+                                       u32 b;
+                                       b = (*f)->buf.bytesused;
+                                       (*f)->state = F_DONE;
+                                       (*f)->buf.sequence= ++cam->frame_count;
+                                       spin_lock(&cam->queue_lock);
+                                       list_move_tail(&(*f)->frame,
+                                                      &cam->outqueue);
+                                       if (!list_empty(&cam->inqueue))
+                                               (*f) = list_entry(
+                                                       cam->inqueue.next,
+                                                       struct sn9c102_frame_t,
+                                                       frame );
+                                       else
+                                               (*f) = NULL;
+                                       spin_unlock(&cam->queue_lock);
+                                       memcpy(cam->sysfs.frame_header,
+                                              cam->sof_header, soflen);
+                                       DBG(3, "Video frame captured: %lu "
+                                              "bytes", (unsigned long)(b));
+
+                                       if (!(*f))
+                                               goto resubmit_urb;
+
+                               } else if (eof) {
+                                       (*f)->state = F_ERROR;
+                                       DBG(3, "Not expected EOF after %lu "
+                                              "bytes of image data",
+                                           (unsigned long)
+                                           ((*f)->buf.bytesused));
+                               }
+
+                               if (sof) /* (1) */
+                                       goto start_of_frame;
+
+                       } else if (eof) {
+                               DBG(3, "EOF without SOF");
+                               continue;
+
+                       } else {
+                               PDBGG("Ignoring pointless isochronous frame");
+                               continue;
+                       }
+
+               } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
+start_of_frame:
+                       (*f)->state = F_GRABBING;
+                       (*f)->buf.bytesused = 0;
+                       len -= (sof - pos);
+                       pos = sof;
+                       DBG(3, "SOF detected: new video frame");
+                       if (len)
+                               goto redo;
+
+               } else if ((*f)->state == F_GRABBING) {
+                       eof = sn9c102_find_eof_header(cam, pos, len);
+                       if (eof && eof < sof)
+                               goto end_of_frame; /* (1) */
+                       else {
+                               if (cam->sensor.pix_format.pixelformat ==
+                                   V4L2_PIX_FMT_SN9C10X) {
+                                       eof = sof - soflen;
+                                       goto end_of_frame;
+                               } else {
+                                       DBG(3, "SOF before expected EOF after "
+                                              "%lu bytes of image data",
+                                           (unsigned long)
+                                           ((*f)->buf.bytesused));
+                                       goto start_of_frame;
+                               }
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int sn9c102_start_transfer(struct sn9c102_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+                                                      680, 800, 900, 1023};
+       const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+                                                      680, 800, 900, 1003};
+       const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
+                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
+                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < SN9C102_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < SN9C102_URBS; i++) {
+               urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = SN9C102_ISO_PACKETS;
+               urb->complete = sn9c102_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       /* Enable video */
+       if (!(cam->reg[0x01] & 0x04)) {
+               err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
+               if (err) {
+                       err = -EIO;
+                       DBG(1, "I/O hardware error");
+                       goto free_urbs;
+               }
+       }
+
+       err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < SN9C102_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < SN9C102_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int sn9c102_stop_transfer(struct sn9c102_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = SN9C102_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    SN9C102_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. "
+                      "To use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
+{
+       char str[5];
+       char* endp;
+       unsigned long val;
+
+       if (len < 4) {
+               strncpy(str, buff, len);
+               str[len+1] = '\0';
+       } else {
+               strncpy(str, buff, 4);
+               str[4] = '\0';
+       }
+
+       val = simple_strtoul(str, &endp, 0);
+
+       *count = 0;
+       if (val <= 0xff)
+               *count = (ssize_t)(endp - str);
+       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
+               *count += 1;
+
+       return (u8)val;
+}
+
+/*
+   NOTE 1: being inside one of the following methods implies that the v4l
+          device exists for sure (see kobjects and reference counters)
+   NOTE 2: buffers are PAGE_SIZE long
+*/
+
+static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.reg);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = sn9c102_strtou8(buf, len, &count);
+       if (index > 0x1f || !count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.reg = index;
+
+       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
+       if (err) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = sn9c102_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.i2c_reg = index;
+
+       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
+       if (err) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.i2c_reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       enum sn9c102_bridge bridge;
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       bridge = cam->bridge;
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count)
+               return -EINVAL;
+
+       switch (bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               if (value > 0x0f)
+                       return -EINVAL;
+               if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
+                       res = sn9c102_store_val(cd, buf, len);
+               break;
+       case BRIDGE_SN9C103:
+               if (value > 0x7f)
+                       return -EINVAL;
+               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+                       res = sn9c102_store_val(cd, buf, len);
+               break;
+       }
+
+       return res;
+}
+
+
+static ssize_t
+sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+{
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count || value > 0x7f)
+               return -EINVAL;
+
+       if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
+               res = sn9c102_store_val(cd, buf, len);
+
+       return res;
+}
+
+
+static ssize_t
+sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+{
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count || value > 0x7f)
+               return -EINVAL;
+
+       if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
+               res = sn9c102_store_val(cd, buf, len);
+
+       return res;
+}
+
+
+static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam)
+               return -ENODEV;
+
+       count = sizeof(cam->sysfs.frame_header);
+       memcpy(buf, cam->sysfs.frame_header, count);
+
+       DBG(3, "Frame header, read bytes: %zd", count);
+
+       return count;
+}
+
+
+static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+                        sn9c102_show_reg, sn9c102_store_reg);
+static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+                        sn9c102_show_val, sn9c102_store_val);
+static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+                        sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
+static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+                        sn9c102_show_i2c_val, sn9c102_store_i2c_val);
+static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
+static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
+                        sn9c102_show_frame_header, NULL);
+
+
+static void sn9c102_create_sysfs(struct sn9c102_device* cam)
+{
+       struct video_device *v4ldev = cam->v4ldev;
+
+       video_device_create_file(v4ldev, &class_device_attr_reg);
+       video_device_create_file(v4ldev, &class_device_attr_val);
+       video_device_create_file(v4ldev, &class_device_attr_frame_header);
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+               video_device_create_file(v4ldev, &class_device_attr_green);
+       else if (cam->bridge == BRIDGE_SN9C103) {
+               video_device_create_file(v4ldev, &class_device_attr_blue);
+               video_device_create_file(v4ldev, &class_device_attr_red);
+       }
+       if (cam->sensor.sysfs_ops) {
+               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+       }
+}
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+/*****************************************************************************/
+
+static int
+sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
+       else
+               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+
+       return err ? -EIO : 0;
+}
+
+
+static int
+sn9c102_set_compression(struct sn9c102_device* cam,
+                       struct v4l2_jpegcompression* compression)
+{
+       int err = 0;
+
+       if (compression->quality == 0)
+               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+       else if (compression->quality == 1)
+               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+
+       return err ? -EIO : 0;
+}
+
+
+static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
+{
+       u8 r = 0;
+       int err = 0;
+
+       if (scale == 1)
+               r = cam->reg[0x18] & 0xcf;
+       else if (scale == 2) {
+               r = cam->reg[0x18] & 0xcf;
+               r |= 0x10;
+       } else if (scale == 4)
+               r = cam->reg[0x18] | 0x20;
+
+       err += sn9c102_write_reg(cam, r, 0x18);
+       if (err)
+               return -EIO;
+
+       PDBGG("Scaling factor: %u", scale);
+
+       return 0;
+}
+
+
+static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
+          v_start = (u8)(rect->top - s->cropcap.bounds.top),
+          h_size = (u8)(rect->width / 16),
+          v_size = (u8)(rect->height / 16);
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+       err += sn9c102_write_reg(cam, h_size, 0x15);
+       err += sn9c102_write_reg(cam, v_size, 0x16);
+       if (err)
+               return -EIO;
+
+       PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
+             "%u %u %u %u", h_start, v_start, h_size, v_size);
+
+       return 0;
+}
+
+
+static int sn9c102_init(struct sn9c102_device* cam)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
+       err += sn9c102_set_crop(cam, rect);
+       if (err)
+               return err;
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED))
+               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
+       else
+               err += sn9c102_set_compression(cam, &cam->compression);
+       err += sn9c102_set_pix_format(cam, &s->pix_format);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, &s->pix_format);
+       if (err)
+               return err;
+
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+               DBG(3, "Compressed video format is active, quality %d",
+                   cam->compression.quality);
+       else
+               DBG(3, "Uncompressed video format is active");
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void sn9c102_release_resources(struct sn9c102_device* cam)
+{
+       mutex_lock(&sn9c102_sysfs_lock);
+
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+
+       usb_put_dev(cam->usbdev);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int sn9c102_open(struct inode* inode, struct file* filp)
+{
+       struct sn9c102_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&sn9c102_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&sn9c102_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&sn9c102_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&sn9c102_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = sn9c102_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = sn9c102_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       sn9c102_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&sn9c102_disconnect);
+       return err;
+}
+
+
+static int sn9c102_release(struct inode* inode, struct file* filp)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       sn9c102_stop_transfer(cam);
+
+       sn9c102_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               sn9c102_release_resources(cam);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose "
+                      "the read method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       sn9c102_empty_framequeues(cam);
+               sn9c102_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       sn9c102_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return count;
+}
+
+
+static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
+                                            IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               sn9c102_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void sn9c102_vm_open(struct vm_area_struct* vma)
+{
+       struct sn9c102_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void sn9c102_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct sn9c102_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct sn9c102_vm_ops = {
+       .open = sn9c102_vm_open,
+       .close = sn9c102_vm_close,
+};
+
+
+static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &sn9c102_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       sn9c102_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "sn9c102",
+               .version = SN9C102_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id && ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+             (unsigned long)ctrl.id, (unsigned long)ctrl.value);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_pix_format* pix_format = &(s->pix_format);
+       u8 scale;
+       const enum sn9c102_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       /* Preserve R,G or B origin */
+       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+       if (rect->width < 16)
+               rect->width = 16;
+       if (rect->height < 16)
+               rect->height = 16;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+
+       rect->width &= ~15L;
+       rect->height &= ~15L;
+
+       if (SN9C102_PRESERVE_IMGSCALE) {
+               /* Calculate the actual scaling factor */
+               u32 a, b;
+               a = rect->width * rect->height;
+               b = pix_format->width * pix_format->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       } else
+               scale = 1;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               sn9c102_release_buffers(cam);
+
+       err = sn9c102_set_crop(cam, rect);
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+       err += sn9c102_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width/scale;
+       s->pix_format.height = rect->height/scale;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
+           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               sn9c102_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               sn9c102_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+       } else if (fmtd.index == 1) {
+               strcpy(fmtd.description, "compressed");
+               fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
+                        void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       u8 scale;
+       const enum sn9c102_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       { /* calculate the actual scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       }
+
+       rect.width = scale * pix->width;
+       rect.height = scale * pix->height;
+
+       if (rect.width < 16)
+               rect.width = 16;
+       if (rect.height < 16)
+               rect.height = 16;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+
+       rect.width &= ~15L;
+       rect.height &= ~15L;
+
+       { /* adjust the scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       }
+
+       pix->width = rect.width / scale;
+       pix->height = rect.height / scale;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+               pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+                           ? 0 : (pix->width * pix->priv) / 8;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. Unmap the "
+                                      "buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap  || cam->io == IO_READ)
+               sn9c102_release_buffers(cam);
+
+       err += sn9c102_set_pix_format(cam, pix);
+       err += sn9c102_set_crop(cam, &rect);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, pix);
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+       err += sn9c102_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               sn9c102_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               sn9c102_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression,
+                        sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum sn9c102_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0 && jc.quality != 1)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       err += sn9c102_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
+                              "still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       sn9c102_empty_framequeues(cam);
+
+       sn9c102_release_buffers(cam);
+       if (rb.count)
+               rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               sn9c102_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
+                    void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct sn9c102_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       sn9c102_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+               sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
+                             unsigned int cmd, void __user * arg)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return sn9c102_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return sn9c102_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return sn9c102_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return sn9c102_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return sn9c102_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return sn9c102_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return sn9c102_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return sn9c102_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return sn9c102_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return sn9c102_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return sn9c102_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return sn9c102_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return sn9c102_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return sn9c102_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return sn9c102_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return sn9c102_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return sn9c102_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return sn9c102_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return sn9c102_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return sn9c102_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return sn9c102_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return sn9c102_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int sn9c102_ioctl(struct inode* inode, struct file* filp,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "sn9c102", cmd);
+
+       err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+/*****************************************************************************/
+
+static struct file_operations sn9c102_fops = {
+       .owner = THIS_MODULE,
+       .open =    sn9c102_open,
+       .release = sn9c102_release,
+       .ioctl =   sn9c102_ioctl,
+       .read =    sn9c102_read,
+       .poll =    sn9c102_poll,
+       .mmap =    sn9c102_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+/* It exists a single interface only. We do not need to validate anything. */
+static int
+sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct sn9c102_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0, r;
+
+       if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       r = sn9c102_read_reg(cam, 0x00);
+       if (r < 0 || r != 0x10) {
+               DBG(1, "Sorry, this is not a SN9C10x based camera "
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+               err = -ENODEV;
+               goto fail;
+       }
+
+       cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
+                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               DBG(2, "SN9C10[12] PC Camera Controller detected "
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+               break;
+       case BRIDGE_SN9C103:
+               DBG(2, "SN9C103 PC Camera Controller detected "
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+               break;
+       }
+
+       for  (i = 0; sn9c102_sensor_table[i]; i++) {
+               err = sn9c102_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err) {
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+               DBG(3, "Support for %s maintained by %s",
+                   cam->sensor.name, cam->sensor.maintainer);
+       } else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (sn9c102_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &sn9c102_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       sn9c102_create_sysfs(cam);
+       DBG(2, "Optional device control through 'sysfs' interface ready");
+#endif
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void sn9c102_usb_disconnect(struct usb_interface* intf)
+{
+       struct sn9c102_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&sn9c102_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               sn9c102_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               sn9c102_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&sn9c102_disconnect);
+}
+
+
+static struct usb_driver sn9c102_usb_driver = {
+       .name =       "sn9c102",
+       .id_table =   sn9c102_id_table,
+       .probe =      sn9c102_usb_probe,
+       .disconnect = sn9c102_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init sn9c102_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
+       KDBG(3, SN9C102_MODULE_AUTHOR);
+
+       if ((err = usb_register(&sn9c102_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit sn9c102_module_exit(void)
+{
+       usb_deregister(&sn9c102_usb_driver);
+}
+
+
+module_init(sn9c102_module_init);
+module_exit(sn9c102_module_exit);
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
new file mode 100644 (file)
index 0000000..c4117bf
--- /dev/null
@@ -0,0 +1,271 @@
+/***************************************************************************
+ * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor hv7131d;
+
+
+static int hv7131d_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x0e, 0x18);
+       err += sn9c102_write_reg(cam, 0xf2, 0x19);
+
+       err += sn9c102_i2c_write(cam, 0x01, 0x04);
+       err += sn9c102_i2c_write(cam, 0x02, 0x00);
+       err += sn9c102_i2c_write(cam, 0x28, 0x00);
+
+       return err;
+}
+
+
+static int hv7131d_get_ctrl(struct sn9c102_device* cam,
+                           struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x26),
+                           r2 = sn9c102_i2c_read(cam, 0x27);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 8) | (r2 & 0xff);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
+                       return -EIO;
+               ctrl->value = 0x3f - (ctrl->value & 0x3f);
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
+                       return -EIO;
+               ctrl->value = 0x3f - (ctrl->value & 0x3f);
+               return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
+                       return -EIO;
+               ctrl->value = 0x3f - (ctrl->value & 0x3f);
+               return 0;
+       case SN9C102_V4L2_CID_RESET_LEVEL:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x3f;
+               return 0;
+       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x07;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int hv7131d_set_ctrl(struct sn9c102_device* cam,
+                           const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
+               err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_RESET_LEVEL:
+               err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
+               err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int hv7131d_set_crop(struct sn9c102_device* cam,
+                           const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &hv7131d;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int hv7131d_set_pix_format(struct sn9c102_device* cam,
+                                 const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x42, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0xf2, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor hv7131d = {
+       .name = "HV7131D",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x11,
+       .init = &hv7131d_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x0250,
+                       .maximum = 0xffff,
+                       .step = 0x0001,
+                       .default_value = 0x0250,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x1e,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_RESET_LEVEL,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "reset level",
+                       .minimum = 0x19,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x30,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "pixel bias voltage",
+                       .minimum = 0x00,
+                       .maximum = 0x07,
+                       .step = 0x01,
+                       .default_value = 0x02,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &hv7131d_get_ctrl,
+       .set_ctrl = &hv7131d_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &hv7131d_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &hv7131d_set_pix_format
+};
+
+
+int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       if (r0 != 0x00 && r1 != 0x04)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &hv7131d);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
new file mode 100644 (file)
index 0000000..4169ea4
--- /dev/null
@@ -0,0 +1,363 @@
+/***************************************************************************
+ * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor mi0343;
+static u8 mi0343_i2c_data[5+1];
+
+
+static int mi0343_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x0a, 0x14);
+       err += sn9c102_write_reg(cam, 0x40, 0x01);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x07, 0x18);
+       err += sn9c102_write_reg(cam, 0xa0, 0x19);
+
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x0d, 0x00, 0x01, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x0d, 0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x03, 0x01, 0xe1, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x04, 0x02, 0x81, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x05, 0x00, 0x17, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x06, 0x00, 0x11, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x62, 0x04, 0x9a, 0, 0);
+
+       return err;
+}
+
+
+static int mi0343_get_ctrl(struct sn9c102_device* cam,
+                          struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x09, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               ctrl->value = mi0343_i2c_data[2];
+               return 0;
+       case V4L2_CID_GAIN:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x35, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_HFLIP:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x20, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
+               return 0;
+       case V4L2_CID_VFLIP:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x20, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x2d, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x2c, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x2e, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+       case V4L2_CID_RED_BALANCE:
+       case V4L2_CID_BLUE_BALANCE:
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
+               if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
+                       ctrl->value -= 0x10;
+               else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
+                       ctrl->value -= 0x60;
+               else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
+                       ctrl->value -= 0xe0;
+       }
+
+       return 0;
+}
+
+
+static int mi0343_set_ctrl(struct sn9c102_device* cam,
+                          const struct v4l2_control* ctrl)
+{
+       u16 reg = 0;
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+       case V4L2_CID_RED_BALANCE:
+       case V4L2_CID_BLUE_BALANCE:
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if (ctrl->value <= (0x3f-0x10))
+                       reg = 0x10 + ctrl->value;
+               else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
+                       reg = 0x60 + (ctrl->value - (0x3f-0x10));
+               else
+                       reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
+               break;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x09, ctrl->value, 0x00,
+                                                0, 0);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x35, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       case V4L2_CID_HFLIP:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x20, ctrl->value ? 0x40:0x00,
+                                                ctrl->value ? 0x20:0x00,
+                                                0, 0);
+               break;
+       case V4L2_CID_VFLIP:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x20, ctrl->value ? 0x80:0x00,
+                                                ctrl->value ? 0x80:0x00,
+                                                0, 0);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2d, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2c, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2b, reg >> 8, reg & 0xff,
+                                                0, 0);
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2e, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int mi0343_set_crop(struct sn9c102_device* cam,
+                           const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &mi0343;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int mi0343_set_pix_format(struct sn9c102_device* cam,
+                                const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x0a, 0x00, 0x03, 0, 0);
+               err += sn9c102_write_reg(cam, 0x20, 0x19);
+       } else {
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x0a, 0x00, 0x05, 0, 0);
+               err += sn9c102_write_reg(cam, 0xa0, 0x19);
+       }
+
+       return err;
+}
+
+
+static struct sn9c102_sensor mi0343 = {
+       .name = "MI-0343",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x5d,
+       .init = &mi0343_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x06,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_HFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "horizontal mirror",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical mirror",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &mi0343_get_ctrl,
+       .set_ctrl = &mi0343_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &mi0343_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &mi0343_set_pix_format
+};
+
+
+int sn9c102_probe_mi0343(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
+                                    2, mi0343_i2c_data) < 0)
+               return -EIO;
+
+       if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &mi0343);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
new file mode 100644 (file)
index 0000000..3da0420
--- /dev/null
@@ -0,0 +1,401 @@
+/***************************************************************************
+ * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor ov7630;
+
+
+static int ov7630_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x0f, 0x18);
+       err += sn9c102_write_reg(cam, 0x50, 0x19);
+
+       err += sn9c102_i2c_write(cam, 0x12, 0x80);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+       err += sn9c102_i2c_write(cam, 0x15, 0x34);
+       err += sn9c102_i2c_write(cam, 0x16, 0x03);
+       err += sn9c102_i2c_write(cam, 0x17, 0x1c);
+       err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+       err += sn9c102_i2c_write(cam, 0x19, 0x06);
+       err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+       err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+       err += sn9c102_i2c_write(cam, 0x20, 0xf6);
+       err += sn9c102_i2c_write(cam, 0x23, 0xee);
+       err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+       err += sn9c102_i2c_write(cam, 0x28, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x29, 0x30);
+       err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
+       err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+       err += sn9c102_i2c_write(cam, 0x30, 0x24);
+       err += sn9c102_i2c_write(cam, 0x32, 0x86);
+       err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x61, 0x42);
+       err += sn9c102_i2c_write(cam, 0x65, 0x00);
+       err += sn9c102_i2c_write(cam, 0x69, 0x38);
+       err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+       err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+       err += sn9c102_i2c_write(cam, 0x71, 0x00);
+       err += sn9c102_i2c_write(cam, 0x74, 0x21);
+       err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+
+       return err;
+}
+
+
+static int ov7630_set_ctrl(struct sn9c102_device* cam,
+                          const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
+               err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+               break;
+       case V4L2_CID_CONTRAST:
+               err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
+                                                      (ctrl->value-1) | 0x20)
+                                  : sn9c102_i2c_write(cam, 0x05, 0x00);
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
+               break;
+       case V4L2_CID_SATURATION:
+               err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
+               break;
+       case V4L2_CID_HUE:
+               err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
+                                                      (ctrl->value-1) | 0x20)
+                                  : sn9c102_i2c_write(cam, 0x04, 0x00);
+               break;
+       case V4L2_CID_DO_WHITE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       case V4L2_CID_WHITENESS:
+               err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
+               break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
+               break;
+       case V4L2_CID_AUTOGAIN:
+               err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
+               break;
+       case V4L2_CID_VFLIP:
+               err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
+               break;
+       case V4L2_CID_BLACK_LEVEL:
+               err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_BRIGHT_LEVEL:
+               err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GAMMA:
+               err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
+               break;
+       case SN9C102_V4L2_CID_BAND_FILTER:
+               err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int ov7630_set_crop(struct sn9c102_device* cam,
+                          const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &ov7630;
+       int err = 0;
+       u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int ov7630_set_pix_format(struct sn9c102_device* cam,
+                                const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x20, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0x50, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor ov7630 = {
+       .name = "OV7630",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x21,
+       .init = &ov7630_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x14,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_HUE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "hue",
+                       .minimum = 0x00,
+                       .maximum = 0x1f+1,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_SATURATION,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "saturation",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x08,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_CONTRAST,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "contrast",
+                       .minimum = 0x00,
+                       .maximum = 0x1f+1,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x000,
+                       .maximum = 0x3ff,
+                       .step = 0x001,
+                       .default_value = 0x83<<2,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x3a,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x77,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BRIGHTNESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "brightness",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0xa0,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_DO_WHITE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "white balance background: blue",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_WHITENESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "white balance background: red",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "auto white balance",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_AUTOGAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "gain & exposure mode",
+                       .minimum = 0x00,
+                       .maximum = 0x03,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical flip",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLACK_LEVEL,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "black pixel ratio",
+                       .minimum = 0x01,
+                       .maximum = 0x9a,
+                       .step = 0x01,
+                       .default_value = 0x8a,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "bright pixel ratio",
+                       .minimum = 0x01,
+                       .maximum = 0x9a,
+                       .step = 0x01,
+                       .default_value = 0x10,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_BAND_FILTER,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "band filter",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GAMMA,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "rgb gamma",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &ov7630_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &ov7630_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &ov7630_set_pix_format
+};
+
+
+int sn9c102_probe_ov7630(struct sn9c102_device* cam)
+{
+       const struct usb_device_id ov7630_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x602c), },
+               { USB_DEVICE(0x0c45, 0x602d), },
+               { USB_DEVICE(0x0c45, 0x608f), },
+               { USB_DEVICE(0x0c45, 0x60b0), },
+               { }
+       };
+       int err = 0;
+
+       if (!sn9c102_match_id(cam, ov7630_id_table))
+               return -ENODEV;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
+       if (err)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &ov7630);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
new file mode 100644 (file)
index 0000000..9915944
--- /dev/null
@@ -0,0 +1,307 @@
+/***************************************************************************
+ * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas106b;
+
+
+static int pas106b_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x20, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x0c);
+       err += sn9c102_i2c_write(cam, 0x05, 0x5a);
+       err += sn9c102_i2c_write(cam, 0x06, 0x88);
+       err += sn9c102_i2c_write(cam, 0x07, 0x80);
+       err += sn9c102_i2c_write(cam, 0x10, 0x06);
+       err += sn9c102_i2c_write(cam, 0x11, 0x06);
+       err += sn9c102_i2c_write(cam, 0x12, 0x00);
+       err += sn9c102_i2c_write(cam, 0x14, 0x02);
+       err += sn9c102_i2c_write(cam, 0x13, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas106b_get_ctrl(struct sn9c102_device* cam,
+                           struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x03),
+                           r2 = sn9c102_i2c_read(cam, 0x04);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 4) | (r2 & 0x0f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_CONTRAST:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x07;
+               return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
+                       return -EIO;
+               ctrl->value = (ctrl->value & 0x1f) << 1;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+                       return -EIO;
+               ctrl->value &= 0xf8;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas106b_set_ctrl(struct sn9c102_device* cam,
+                           const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
+               break;
+       case V4L2_CID_CONTRAST:
+               err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
+               err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x13, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas106b_set_crop(struct sn9c102_device* cam,
+                           const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas106b;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int pas106b_set_pix_format(struct sn9c102_device* cam,
+                                 const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x2c, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas106b = {
+       .name = "PAS106B",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas106b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x125,
+                       .maximum = 0xfff,
+                       .step = 0x001,
+                       .default_value = 0x140,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0d,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_CONTRAST,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "contrast",
+                       .minimum = 0x00,
+                       .maximum = 0x07,
+                       .step = 0x01,
+                       .default_value = 0x00, /* 0x00~0x03 have same effect */
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x06,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3e,
+                       .step = 0x02,
+                       .default_value = 0x02,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &pas106b_get_ctrl,
+       .set_ctrl = &pas106b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+       },
+       .set_crop = &pas106b_set_crop,
+       .pix_format = {
+               .width = 352,
+               .height = 288,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8, /* we use this field as 'bits per pixel' */
+       },
+       .set_pix_format = &pas106b_set_pix_format
+};
+
+
+int sn9c102_probe_pas106b(struct sn9c102_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       /*
+          Minimal initialization to enable the I2C communication
+          NOTE: do NOT change the values!
+       */
+       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
+       err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
+       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
+
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x007)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas106b);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c
new file mode 100644 (file)
index 0000000..c8f1ae2
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bca;
+
+
+static int pas202bca_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x30, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x14);
+       err += sn9c102_i2c_write(cam, 0x03, 0x40);
+       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x10, 0x08);
+       err += sn9c102_i2c_write(cam, 0x13, 0x63);
+       err += sn9c102_i2c_write(cam, 0x15, 0x70);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas202bca_set_pix_format(struct sn9c102_device* cam,
+                                   const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x24, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static int pas202bca_set_ctrl(struct sn9c102_device* cam,
+                             const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas202bca_set_crop(struct sn9c102_device* cam,
+                             const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas202bca;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas202bca = {
+       .name = "PAS202BCA",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas202bca_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &pas202bca_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &pas202bca_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &pas202bca_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
+{
+       const struct usb_device_id pas202bca_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x60af), },
+               { }
+       };
+       int err = 0;
+
+       if (!sn9c102_match_id(cam,pas202bca_id_table))
+               return -ENODEV;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x40, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas202bca);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
new file mode 100644 (file)
index 0000000..e3c1178
--- /dev/null
@@ -0,0 +1,293 @@
+/***************************************************************************
+ * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
+ *                       <medaglia@undl.org.br>                            *
+ *                       http://cadu.homelinux.com:8080/                   *
+ *                                                                         *
+ * DAC Magnitude, exposure and green gain controls added by                *
+ * Luca Risolia <luca.risolia@studio.unibo.it>                             *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x30, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x14);
+       err += sn9c102_i2c_write(cam, 0x03, 0x40);
+       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x10, 0x08);
+       err += sn9c102_i2c_write(cam, 0x13, 0x63);
+       err += sn9c102_i2c_write(cam, 0x15, 0x70);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
+                             struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x04),
+                           r2 = sn9c102_i2c_read(cam, 0x05);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+                       return -EIO;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
+                                   const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x24, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
+                             const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas202bcb_set_crop(struct sn9c102_device* cam,
+                             const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas202bcb;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas202bcb = {
+       .name = "PAS202BCB",
+       .maintainer = "Carlos Eduardo Medaglia Dyonisio "
+                     "<medaglia@undl.org.br>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas202bcb_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &pas202bcb_get_ctrl,
+       .set_ctrl = &pas202bcb_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &pas202bcb_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &pas202bcb_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       /*
+        *  Minimal initialization to enable the I2C communication
+        *  NOTE: do NOT change the values!
+        */
+       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
+       err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
+       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
+
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x017)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas202bcb);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
new file mode 100644 (file)
index 0000000..2a874ee
--- /dev/null
@@ -0,0 +1,389 @@
+/***************************************************************************
+ * API for image sensors connected to the SN9C10x PC Camera Controllers    *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _SN9C102_SENSOR_H_
+#define _SN9C102_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct sn9c102_device;
+struct sn9c102_sensor;
+
+/*****************************************************************************/
+
+/*
+   OVERVIEW.
+   This is a small interface that allows you to add support for any CCD/CMOS
+   image sensors connected to the SN9C10X bridges. The entire API is documented
+   below. In the most general case, to support a sensor there are three steps
+   you have to follow:
+   1) define the main "sn9c102_sensor" structure by setting the basic fields;
+   2) write a probing function to be called by the core module when the USB
+      camera is recognized, then add both the USB ids and the name of that
+      function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
+      below);
+   3) implement the methods that you want/need (and fill the rest of the main
+      structure accordingly).
+   "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
+   NOT need to touch the source code of the core module for the things to work
+   properly, unless you find bugs or flaws in it. Finally, do not forget to
+   read the V4L2 API for completeness.
+*/
+
+/*****************************************************************************/
+
+/*
+   Probing functions: on success, you must attach the sensor to the camera
+   by calling sn9c102_attach_sensor() provided below.
+   To enable the I2C communication, you might need to perform a really basic
+   initialization of the SN9C10X chip by using the write function declared
+   ahead.
+   Functions must return 0 on success, the appropriate error otherwise.
+*/
+extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
+
+/*
+   Add the above entries to this table. Be sure to add the entry in the right
+   place, since, on failure, the next probing routine is called according to
+   the order of the list below, from top to bottom.
+*/
+#define SN9C102_SENSOR_TABLE                                                  \
+static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
+       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */     \
+       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
+       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
+       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
+       &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
+       &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
+       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
+       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
+       NULL,                                                                 \
+};
+
+/* Device identification */
+extern struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
+
+/* Attach a probed sensor to the camera. */
+extern void
+sn9c102_attach_sensor(struct sn9c102_device* cam,
+                     struct sn9c102_sensor* sensor);
+
+/*
+   Each SN9C10x camera has proper PID/VID identifiers.
+   SN9C103 supports multiple interfaces, but we only handle the video class
+   interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = (intclass)
+
+#define SN9C102_ID_TABLE                                                      \
+static const struct usb_device_id sn9c102_id_table[] = {                      \
+       { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6007), },                                      \
+       { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x6024), },                                      \
+       { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */      \
+       { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */                      \
+       { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */                        \
+       { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
+       { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
+       { USB_DEVICE(0x0c45, 0x602d), },                                      \
+       { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
+       { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
+       { }                                                                   \
+};
+
+/*****************************************************************************/
+
+/*
+   Read/write routines: they always return -1 on error, 0 or the read value
+   otherwise. NOTE that a real read operation is not supported by the SN9C10X
+   chip for some of its registers. To work around this problem, a pseudo-read
+   call is provided instead: it returns the last successfully written value
+   on the register (0 if it has never been written), the usual -1 on error.
+*/
+
+/* The "try" I2C I/O versions are used when probing the sensor */
+extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*,
+                                u8 address, u8 value);
+extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
+                               u8 address);
+
+/*
+   These must be used if and only if the sensor doesn't implement the standard
+   I2C protocol. There are a number of good reasons why you must use the
+   single-byte versions of these functions: do not abuse. The first function
+   writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
+   chip. The second one programs the registers 0x09 and 0x10 with data0 and
+   data1, and places the n bytes read from the sensor register table in the
+   buffer pointed by 'buffer'. Both the functions return -1 on error; the write
+   version returns 0 on success, while the read version returns the first read
+   byte.
+*/
+extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
+                                    struct sn9c102_sensor* sensor, u8 n,
+                                    u8 data0, u8 data1, u8 data2, u8 data3,
+                                    u8 data4, u8 data5);
+extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
+                                   struct sn9c102_sensor* sensor, u8 data0,
+                                   u8 data1, u8 n, u8 buffer[]);
+
+/* To be used after the sensor struct has been attached to the camera struct */
+extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
+extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
+
+/* I/O on registers in the bridge. Could be used by the sensor methods too */
+extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
+extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
+extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
+
+/*
+   NOTE: there are no exported debugging functions. To uniform the output you
+   must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
+   already included here, the argument being the struct device '&usbdev->dev'
+   of the sensor structure. Do NOT use these macros before the sensor is
+   attached or the kernel will crash! However, you should not need to notify
+   the user about common errors or other messages, since this is done by the
+   master module.
+*/
+
+/*****************************************************************************/
+
+enum sn9c102_i2c_sysfs_ops {
+       SN9C102_I2C_READ = 0x01,
+       SN9C102_I2C_WRITE = 0x02,
+};
+
+enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */
+       SN9C102_I2C_100KHZ = 0x01,
+       SN9C102_I2C_400KHZ = 0x02,
+};
+
+enum sn9c102_i2c_interface {
+       SN9C102_I2C_2WIRES,
+       SN9C102_I2C_3WIRES,
+};
+
+#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+
+struct sn9c102_sensor {
+       char name[32], /* sensor name */
+            maintainer[64]; /* name of the mantainer <email> */
+
+       /* Supported operations through the 'sysfs' interface */
+       enum sn9c102_i2c_sysfs_ops sysfs_ops;
+
+       /*
+          These sensor capabilities must be provided if the SN9C10X controller
+          needs to communicate through the sensor serial interface by using
+          at least one of the i2c functions available.
+       */
+       enum sn9c102_i2c_frequency frequency;
+       enum sn9c102_i2c_interface interface;
+
+       /*
+          This identifier must be provided if the image sensor implements
+          the standard I2C protocol.
+       */
+       u8 i2c_slave_id; /* reg. 0x09 */
+
+       /*
+          NOTE: Where not noted,most of the functions below are not mandatory.
+                Set to null if you do not implement them. If implemented,
+                they must return 0 on success, the proper error otherwise.
+       */
+
+       int (*init)(struct sn9c102_device* cam);
+       /*
+          This function will be called after the sensor has been attached.
+          It should be used to initialize the sensor only, but may also
+          configure part of the SN9C10X chip if necessary. You don't need to
+          setup picture settings like brightness, contrast, etc.. here, if
+          the corrisponding controls are implemented (see below), since
+          they are adjusted in the core driver by calling the set_ctrl()
+          method after init(), where the arguments are the default values
+          specified in the v4l2_queryctrl list of supported controls;
+          Same suggestions apply for other settings, _if_ the corresponding
+          methods are present; if not, the initialization must configure the
+          sensor according to the default configuration structures below.
+       */
+
+       struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
+       /*
+          Optional list of default controls, defined as indicated in the
+          V4L2 API. Menu type controls are not handled by this interface.
+       */
+
+       int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct sn9c102_device* cam,
+                       const struct v4l2_control* ctrl);
+       /*
+          You must implement at least the set_ctrl method if you have defined
+          the list above. The returned value must follow the V4L2
+          specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
+          are not supported by this driver, so do not implement them. Also,
+          you don't have to check whether the passed values are out of bounds,
+          given that this is done by the core module.
+       */
+
+       struct v4l2_cropcap cropcap;
+       /*
+          Think the image sensor as a grid of R,G,B monochromatic pixels
+          disposed according to a particular Bayer pattern, which describes
+          the complete array of pixels, from (0,0) to (xmax, ymax). We will
+          use this coordinate system from now on. It is assumed the sensor
+          chip can be programmed to capture/transmit a subsection of that
+          array of pixels: we will call this subsection "active window".
+          It is not always true that the largest achievable active window can
+          cover the whole array of pixels. The V4L2 API defines another
+          area called "source rectangle", which, in turn, is a subrectangle of
+          the active window. The SN9C10X chip is always programmed to read the
+          source rectangle.
+          The bounds of both the active window and the source rectangle are
+          specified in the cropcap substructures 'bounds' and 'defrect'.
+          By default, the source rectangle should cover the largest possible
+          area. Again, it is not always true that the largest source rectangle
+          can cover the entire active window, although it is a rare case for
+          the hardware we have. The bounds of the source rectangle _must_ be
+          multiple of 16 and must use the same coordinate system as indicated
+          before; their centers shall align initially.
+          If necessary, the sensor chip must be initialized during init() to
+          set the bounds of the active sensor window; however, by default, it
+          usually covers the largest achievable area (maxwidth x maxheight)
+          of pixels, so no particular initialization is needed, if you have
+          defined the correct default bounds in the structures.
+          See the V4L2 API for further details.
+          NOTE: once you have defined the bounds of the active window
+                (struct cropcap.bounds) you must not change them.anymore.
+          Only 'bounds' and 'defrect' fields are mandatory, other fields
+          will be ignored.
+       */
+
+       int (*set_crop)(struct sn9c102_device* cam,
+                       const struct v4l2_rect* rect);
+       /*
+          To be called on VIDIOC_C_SETCROP. The core module always calls a
+          default routine which configures the appropriate SN9C10X regs (also
+          scaling), but you may need to override/adjust specific stuff.
+          'rect' contains width and height values that are multiple of 16: in
+          case you override the default function, you always have to program
+          the chip to match those values; on error return the corresponding
+          error code without rolling back.
+          NOTE: in case, you must program the SN9C10X chip to get rid of
+                blank pixels or blank lines at the _start_ of each line or
+                frame after each HSYNC or VSYNC, so that the image starts with
+                real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
+                V_SIZE you don't have to care about blank pixels or blank
+                lines at the end of each line or frame).
+       */
+
+       struct v4l2_pix_format pix_format;
+       /*
+          What you have to define here are: 1) initial 'width' and 'height' of
+          the target rectangle 2) the initial 'pixelformat', which can be
+          either V4L2_PIX_FMT_SN9C10X (for compressed video) or
+          V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
+          number of bits per pixel for uncompressed video, 8 or 9 (despite the
+          current value of 'pixelformat').
+          NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
+                  of cropcap.defrect.width and cropcap.defrect.height. I
+                  suggest 1/1.
+          NOTE 2: The initial compression quality is defined by the first bit
+                  of reg 0x17 during the initialization of the image sensor.
+          NOTE 3: as said above, you have to program the SN9C10X chip to get
+                  rid of any blank pixels, so that the output of the sensor
+                  matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
+       */
+
+       int (*set_pix_format)(struct sn9c102_device* cam,
+                             const struct v4l2_pix_format* pix);
+       /*
+          To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
+          SN9C10X pixel format or viceversa. On error return the corresponding
+          error code without rolling back.
+       */
+
+       /*
+          Do NOT write to the data below, it's READ ONLY. It is used by the
+          core module to store successfully updated values of the above
+          settings, for rollbacks..etc..in case of errors during atomic I/O
+       */
+       struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+/*****************************************************************************/
+
+/* Private ioctl's for control settings supported by some image sensors */
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
+#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
+#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
+#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
+#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
+
+#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
new file mode 100644 (file)
index 0000000..294eb02
--- /dev/null
@@ -0,0 +1,159 @@
+/***************************************************************************
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor tas5110c1b;
+
+
+static int tas5110c1b_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x44, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x0a, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x06, 0x18);
+       err += sn9c102_write_reg(cam, 0xfb, 0x19);
+
+       err += sn9c102_i2c_write(cam, 0xc0, 0x80);
+
+       return err;
+}
+
+
+static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int tas5110c1b_set_crop(struct sn9c102_device* cam,
+                              const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &tas5110c1b;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       /* Don't change ! */
+       err += sn9c102_write_reg(cam, 0x14, 0x1a);
+       err += sn9c102_write_reg(cam, 0x0a, 0x1b);
+       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
+
+       return err;
+}
+
+
+static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
+                                    const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x2b, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0xfb, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor tas5110c1b = {
+       .name = "TAS5110C1B",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_3WIRES,
+       .init = &tas5110c1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x01,
+                       .default_value = 0x40,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5110c1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+       },
+       .set_crop = &tas5110c1b_set_crop,
+       .pix_format = {
+               .width = 352,
+               .height = 288,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &tas5110c1b_set_pix_format
+};
+
+
+int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
+{
+       const struct usb_device_id tas5110c1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6001), },
+               { USB_DEVICE(0x0c45, 0x6005), },
+               { USB_DEVICE(0x0c45, 0x60ab), },
+               { }
+       };
+
+       /* Sensor detection is based on USB pid/vid */
+       if (!sn9c102_match_id(cam, tas5110c1b_id_table))
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &tas5110c1b);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
new file mode 100644 (file)
index 0000000..9ecb090
--- /dev/null
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor tas5130d1b;
+
+
+static int tas5130d1b_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x04, 0x01);
+       err += sn9c102_write_reg(cam, 0x01, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x07, 0x18);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int tas5130d1b_set_crop(struct sn9c102_device* cam,
+                              const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &tas5130d1b;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       /* Do NOT change! */
+       err += sn9c102_write_reg(cam, 0x1f, 0x1a);
+       err += sn9c102_write_reg(cam, 0x1a, 0x1b);
+       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
+                                    const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x63, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0xf3, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor tas5130d1b = {
+       .name = "TAS5130D1B",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_3WIRES,
+       .init = &tas5130d1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x02,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x47,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5130d1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &tas5130d1b_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &tas5130d1b_set_pix_format
+};
+
+
+int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
+{
+       const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6025), },
+               { USB_DEVICE(0x0c45, 0x60aa), },
+               { }
+       };
+
+       /* Sensor detection is based on USB pid/vid */
+       if (!sn9c102_match_id(cam, tas5130d1b_id_table))
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &tas5130d1b);
+
+       return 0;
+}
index 9d769264a32904c93a18f9f37851eba0ddbfb826..07476c71174a70d05a77164c6f4aa39afd7d59fa 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * stradis.c - stradis 4:2:2 mpeg decoder driver
  *
  * Stradis 4:2:2 MPEG-2 Decoder Driver
@@ -1191,9 +1191,9 @@ static void saa7146_set_winsize(struct saa7146 *saa)
 }
 
 /* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
- * bitmap is fixed width, 128 bytes (1024 pixels represented) 
- * arranged most-sigificant-bit-left in 32-bit words 
- * based on saa7146 clipping hardware, it swaps bytes if LE 
+ * bitmap is fixed width, 128 bytes (1024 pixels represented)
+ * arranged most-sigificant-bit-left in 32-bit words
+ * based on saa7146 clipping hardware, it swaps bytes if LE
  * much of this makes up for egcs brain damage -- so if you
  * are wondering "why did he do this?" it is because the C
  * was adjusted to generate the optimal asm output without
@@ -1259,7 +1259,7 @@ static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
                        clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
                                cr[i].width, cr[i].height);
        }
-       /* clip against viewing window AND screen 
+       /* clip against viewing window AND screen
           so we do not have to rely on the user program
         */
        clip_draw_rectangle(clipmap, (saa->win.x + width > saa->win.swidth) ?
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
new file mode 100644 (file)
index 0000000..b38bda8
--- /dev/null
@@ -0,0 +1,1508 @@
+/*
+ *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
+ *
+ * Thanks to STMicroelectronics for information on the usb commands, and
+ * to Steve Miller at STM for his help and encouragement while I was
+ * writing this driver.
+ *
+ * This driver is based heavily on the
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ * ver 0.1 October, 2001. Initial attempt.
+ *
+ * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
+ *                         function, made more stable (?)
+ *
+ * ver 0.21 Nov, 2001.     Added gamma correction and white balance,
+ *                         due to Alexander Schwartz. Still trying to
+ *                         improve stablility. Moved stuff into stv680.h
+ *
+ * ver 0.22 Nov, 2001.    Added sharpen function (by Michael Sweet,
+ *                         mike@easysw.com) from GIMP, also used in pencam.
+ *                         Simple, fast, good integer math routine.
+ *
+ * ver 0.23 Dec, 2001 (gkh)
+ *                        Took out sharpen function, ran code through
+ *                        Lindent, and did other minor tweaks to get
+ *                        things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs)
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to
+ *                         improve quality. Got rid of green line around
+ *                         frame. Fix brightness reset when changing size
+ *                         bug. Adjusted gamma filters slightly.
+ *
+ * ver 0.25 Jan, 2002 (kjs)
+ *                        Fixed a bug in which the driver sometimes attempted
+ *                        to set to a non-supported size. This allowed
+ *                        gnomemeeting to work.
+ *                        Fixed proc entry removal bug.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#include "stv680.h"
+
+static int video_nr = -1;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
+
+static unsigned int debug = 0;
+
+#define PDEBUG(level, fmt, args...) \
+       do { \
+       if (debug >= level)     \
+               info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \
+       } while (0)
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.25"
+#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
+#define DRIVER_DESC "STV0680 USB Camera Driver"
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC (debug, "Debug enabled or not");
+module_param(swapRGB_on, int, 0);
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
+module_param(video_nr, int, 0);
+
+/********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ *
+ * And the STV0680 driver - Kevin
+ ********************************************************************/
+static void *rvmalloc (unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32 (size);
+       if (!mem)
+               return NULL;
+
+       memset (mem, 0, size);  /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       return mem;
+}
+
+static void rvfree (void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree (mem);
+}
+
+
+/*********************************************************************
+ * pencam read/write functions
+ ********************************************************************/
+
+static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
+{
+       int ret = -1;
+
+       switch (set) {
+       case 0:         /*  0xc1  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_rcvctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       case 1:         /*  0x41  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_sndctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       case 2:         /*  0x80  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_rcvctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_IN | USB_RECIP_DEVICE),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       case 3:         /*  0x40  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_sndctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       }
+       if ((ret < 0) && (req != 0x0a)) {
+               PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
+       }
+       return ret;
+}
+
+static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
+{
+
+       if (configuration != dev->udev->actconfig->desc.bConfigurationValue
+                       || usb_reset_configuration (dev->udev) < 0) {
+               PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
+               return -1;
+       }
+       if (usb_set_interface (dev->udev, interface, alternate) < 0) {
+               PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
+               return -1;
+       }
+       return 0;
+}
+
+static int stv_stop_video (struct usb_stv *dev)
+{
+       int i;
+       unsigned char *buf;
+
+       buf = kmalloc (40, GFP_KERNEL);
+       if (buf == NULL) {
+               PDEBUG (0, "STV(e): Out of (small buf) memory");
+               return -1;
+       }
+
+       /* this is a high priority command; it stops all lower order commands */
+       if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
+               i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);   /* Get Last Error; 2 = busy */
+               PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
+       } else {
+               PDEBUG (1, "STV(i): Camera reset to idle mode.");
+       }
+
+       if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
+               PDEBUG (1, "STV(e): Reset config during exit failed");
+
+       /*  get current mode  */
+       buf[0] = 0xf0;
+       if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)     /* get mode */
+               PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
+       if (dev->origMode != buf[0]) {
+               memset (buf, 0, 8);
+               buf[0] = (unsigned char) dev->origMode;
+               if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
+                       PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
+                       i = -1;
+               }
+               buf[0] = 0xf0;
+               i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
+               if ((i != 0x08) || (buf[0] != dev->origMode)) {
+                       PDEBUG (0, "STV(e): camera NOT set to original resolution.");
+                       i = -1;
+               } else
+                       PDEBUG (0, "STV(i): Camera set to original resolution");
+       }
+       /* origMode */
+       kfree(buf);
+       return i;
+}
+
+static int stv_set_video_mode (struct usb_stv *dev)
+{
+       int i, stop_video = 1;
+       unsigned char *buf;
+
+       buf = kmalloc (40, GFP_KERNEL);
+       if (buf == NULL) {
+               PDEBUG (0, "STV(e): Out of (small buf) memory");
+               return -1;
+       }
+
+       if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
+               kfree(buf);
+               return i;
+       }
+
+       i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
+       if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
+               PDEBUG (1, "STV(e): Could not get descriptor 0100.");
+               goto error;
+       }
+
+       /*  set alternate interface 1 */
+       if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
+               goto error;
+
+       if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
+               goto error;
+       PDEBUG (1, "STV(i): Setting video mode.");
+       /*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
+       if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
+               stop_video = 0;
+               goto error;
+       }
+       goto exit;
+
+error:
+       kfree(buf);
+       if (stop_video == 1)
+               stv_stop_video (dev);
+       return -1;
+
+exit:
+       kfree(buf);
+       return 0;
+}
+
+static int stv_init (struct usb_stv *stv680)
+{
+       int i = 0;
+       unsigned char *buffer;
+       unsigned long int bufsize;
+
+       buffer = kzalloc (40, GFP_KERNEL);
+       if (buffer == NULL) {
+               PDEBUG (0, "STV(e): Out of (small buf) memory");
+               return -1;
+       }
+       udelay (100);
+
+       /* set config 1, interface 0, alternate 0 */
+       if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
+               kfree(buffer);
+               PDEBUG (0, "STV(e): set config 1,0,0 failed");
+               return -1;
+       }
+       /* ping camera to be sure STV0680 is present */
+       if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
+               goto error;
+       if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
+               PDEBUG (1, "STV(e): camera ping failed!!");
+               goto error;
+       }
+
+       /* get camera descriptor */
+       if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
+               goto error;
+       i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
+       if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
+               PDEBUG (1, "STV(e): Could not get descriptor 0200.");
+               goto error;
+       }
+       if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
+               goto error;
+       if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
+               goto error;
+       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+               goto error;
+
+       stv680->SupportedModes = buffer[7];
+       i = stv680->SupportedModes;
+       stv680->CIF = 0;
+       stv680->VGA = 0;
+       stv680->QVGA = 0;
+       if (i & 1)
+               stv680->CIF = 1;
+       if (i & 2)
+               stv680->VGA = 1;
+       if (i & 8)
+               stv680->QVGA = 1;
+       if (stv680->SupportedModes == 0) {
+               PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
+               i = -1;
+               goto error;
+       } else {
+               if (stv680->CIF)
+                       PDEBUG (0, "STV(i): CIF is supported");
+               if (stv680->QVGA)
+                       PDEBUG (0, "STV(i): QVGA is supported");
+       }
+       /* FW rev, ASIC rev, sensor ID  */
+       PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
+       PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
+       PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
+
+       /*  set alternate interface 1 */
+       if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
+               goto error;
+
+       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+               goto error;
+       if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
+               goto error;
+       i = buffer[3];
+       PDEBUG (0, "STV(i): Camera has %i pictures.", i);
+
+       /*  get current mode */
+       if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
+               goto error;
+       stv680->origMode = buffer[0];   /* 01 = VGA, 03 = QVGA, 00 = CIF */
+
+       /* This will attemp CIF mode, if supported. If not, set to QVGA  */
+       memset (buffer, 0, 8);
+       if (stv680->CIF)
+               buffer[0] = 0x00;
+       else if (stv680->QVGA)
+               buffer[0] = 0x03;
+       if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
+               PDEBUG (0, "STV(i): Set_Camera_Mode failed");
+               i = -1;
+               goto error;
+       }
+       buffer[0] = 0xf0;
+       stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
+       if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
+               PDEBUG (0, "STV(e): Error setting camera video mode!");
+               i = -1;
+               goto error;
+       } else {
+               if (buffer[0] == 0) {
+                       stv680->VideoMode = 0x0000;
+                       PDEBUG (0, "STV(i): Video Mode set to CIF");
+               }
+               if (buffer[0] == 0x03) {
+                       stv680->VideoMode = 0x0300;
+                       PDEBUG (0, "STV(i): Video Mode set to QVGA");
+               }
+       }
+       if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
+               goto error;
+       bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
+       stv680->cwidth = (buffer[4] << 8) | (buffer[5]);        /* ->camera = 322, 356, 644  */
+       stv680->cheight = (buffer[6] << 8) | (buffer[7]);       /* ->camera = 242, 292, 484  */
+       stv680->origGain = buffer[12];
+
+       goto exit;
+
+error:
+       i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);     /* Get Last Error */
+       PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
+       kfree(buffer);
+       return -1;
+
+exit:
+       kfree(buffer);
+
+       /* video = 320x240, 352x288 */
+       if (stv680->CIF == 1) {
+               stv680->maxwidth = 352;
+               stv680->maxheight = 288;
+               stv680->vwidth = 352;
+               stv680->vheight = 288;
+       }
+       if (stv680->QVGA == 1) {
+               stv680->maxwidth = 320;
+               stv680->maxheight = 240;
+               stv680->vwidth = 320;
+               stv680->vheight = 240;
+       }
+
+       stv680->rawbufsize = bufsize;   /* must be ./. by 8 */
+       stv680->maxframesize = bufsize * 3;     /* RGB size */
+       PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
+       PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
+
+       /* some default values */
+       stv680->bulk_in_endpointAddr = 0x82;
+       stv680->dropped = 0;
+       stv680->error = 0;
+       stv680->framecount = 0;
+       stv680->readcount = 0;
+       stv680->streaming = 0;
+       /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
+       stv680->brightness = 32767;
+       stv680->chgbright = 0;
+       stv680->whiteness = 0;  /* only for greyscale */
+       stv680->colour = 32767;
+       stv680->contrast = 32767;
+       stv680->hue = 32767;
+       stv680->palette = STV_VIDEO_PALETTE;
+       stv680->depth = 24;     /* rgb24 bits */
+       if ((swapRGB_on == 0) && (swapRGB == 0))
+               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+       else if ((swapRGB_on == 0) && (swapRGB == 1))
+               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+       else if (swapRGB_on == 1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+       else if (swapRGB_on == -1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+
+       if (stv_set_video_mode (stv680) < 0) {
+               PDEBUG (0, "STV(e): Could not set video mode in stv_init");
+               return -1;
+       }
+
+       return 0;
+}
+
+/***************** last of pencam  routines  *******************/
+
+/****************************************************************************
+ *  sysfs
+ ***************************************************************************/
+#define stv680_file(name, variable, field)                             \
+static ssize_t show_##name(struct class_device *class_dev, char *buf)  \
+{                                                                      \
+       struct video_device *vdev = to_video_device(class_dev);         \
+       struct usb_stv *stv = video_get_drvdata(vdev);                  \
+       return sprintf(buf, field, stv->variable);                      \
+}                                                                      \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+stv680_file(model, camera_name, "%s\n");
+stv680_file(in_use, user, "%d\n");
+stv680_file(streaming, streaming, "%d\n");
+stv680_file(palette, palette, "%i\n");
+stv680_file(frames_total, readcount, "%d\n");
+stv680_file(frames_read, framecount, "%d\n");
+stv680_file(packets_dropped, dropped, "%d\n");
+stv680_file(decoding_errors, error, "%d\n");
+
+static void stv680_create_sysfs_files(struct video_device *vdev)
+{
+       video_device_create_file(vdev, &class_device_attr_model);
+       video_device_create_file(vdev, &class_device_attr_in_use);
+       video_device_create_file(vdev, &class_device_attr_streaming);
+       video_device_create_file(vdev, &class_device_attr_palette);
+       video_device_create_file(vdev, &class_device_attr_frames_total);
+       video_device_create_file(vdev, &class_device_attr_frames_read);
+       video_device_create_file(vdev, &class_device_attr_packets_dropped);
+       video_device_create_file(vdev, &class_device_attr_decoding_errors);
+}
+
+static void stv680_remove_sysfs_files(struct video_device *vdev)
+{
+       video_device_remove_file(vdev, &class_device_attr_model);
+       video_device_remove_file(vdev, &class_device_attr_in_use);
+       video_device_remove_file(vdev, &class_device_attr_streaming);
+       video_device_remove_file(vdev, &class_device_attr_palette);
+       video_device_remove_file(vdev, &class_device_attr_frames_total);
+       video_device_remove_file(vdev, &class_device_attr_frames_read);
+       video_device_remove_file(vdev, &class_device_attr_packets_dropped);
+       video_device_remove_file(vdev, &class_device_attr_decoding_errors);
+}
+
+/********************************************************************
+ * Camera control
+ *******************************************************************/
+
+static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+       /* This sets values for v4l interface. max/min = 65535/0  */
+
+       p->brightness = stv680->brightness;
+       p->whiteness = stv680->whiteness;       /* greyscale */
+       p->colour = stv680->colour;
+       p->contrast = stv680->contrast;
+       p->hue = stv680->hue;
+       p->palette = stv680->palette;
+       p->depth = stv680->depth;
+       return 0;
+}
+
+static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+       /* See above stv680_get_pict  */
+
+       if (p->palette != STV_VIDEO_PALETTE) {
+               PDEBUG (2, "STV(e): Palette set error in _set_pic");
+               return 1;
+       }
+
+       if (stv680->brightness != p->brightness) {
+               stv680->chgbright = 1;
+               stv680->brightness = p->brightness;
+       }
+
+       stv680->whiteness = p->whiteness;       /* greyscale */
+       stv680->colour = p->colour;
+       stv680->contrast = p->contrast;
+       stv680->hue = p->hue;
+       stv680->palette = p->palette;
+       stv680->depth = p->depth;
+
+       return 0;
+}
+
+static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_stv *stv680 = urb->context;
+       int length = urb->actual_length;
+
+       if (length < stv680->rawbufsize)
+               PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
+
+       /* ohoh... */
+       if (!stv680->streaming)
+               return;
+
+       if (!stv680->udev) {
+               PDEBUG (0, "STV(e): device vapourished in video_irq");
+               return;
+       }
+
+       /* 0 sized packets happen if we are to fast, but sometimes the camera
+          keeps sending them forever...
+        */
+       if (length && !urb->status) {
+               stv680->nullpackets = 0;
+               switch (stv680->scratch[stv680->scratch_next].state) {
+               case BUFFER_READY:
+               case BUFFER_BUSY:
+                       stv680->dropped++;
+                       break;
+
+               case BUFFER_UNUSED:
+                       memcpy (stv680->scratch[stv680->scratch_next].data,
+                               (unsigned char *) urb->transfer_buffer, length);
+                       stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
+                       stv680->scratch[stv680->scratch_next].length = length;
+                       if (waitqueue_active (&stv680->wq)) {
+                               wake_up_interruptible (&stv680->wq);
+                       }
+                       stv680->scratch_overflow = 0;
+                       stv680->scratch_next++;
+                       if (stv680->scratch_next >= STV680_NUMSCRATCH)
+                               stv680->scratch_next = 0;
+                       break;
+               }               /* switch  */
+       } else {
+               stv680->nullpackets++;
+               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+                       if (waitqueue_active (&stv680->wq)) {
+                               wake_up_interruptible (&stv680->wq);
+                       }
+               }
+       }                       /*  if - else */
+
+       /* Resubmit urb for new data */
+       urb->status = 0;
+       urb->dev = stv680->udev;
+       if (usb_submit_urb (urb, GFP_ATOMIC))
+               PDEBUG (0, "STV(e): urb burned down in video irq");
+       return;
+}                              /*  _video_irq  */
+
+static int stv680_start_stream (struct usb_stv *stv680)
+{
+       struct urb *urb;
+       int err = 0, i;
+
+       stv680->streaming = 1;
+
+       /* Do some memory allocation */
+       for (i = 0; i < STV680_NUMFRAMES; i++) {
+               stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
+               stv680->frame[i].curpix = 0;
+       }
+       /* packet size = 4096  */
+       for (i = 0; i < STV680_NUMSBUF; i++) {
+               stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+               if (stv680->sbuf[i].data == NULL) {
+                       PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
+                       return -1;
+               }
+       }
+
+       stv680->scratch_next = 0;
+       stv680->scratch_use = 0;
+       stv680->scratch_overflow = 0;
+       for (i = 0; i < STV680_NUMSCRATCH; i++) {
+               stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+               if (stv680->scratch[i].data == NULL) {
+                       PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
+                       return -1;
+               }
+               stv680->scratch[i].state = BUFFER_UNUSED;
+       }
+
+       for (i = 0; i < STV680_NUMSBUF; i++) {
+               urb = usb_alloc_urb (0, GFP_KERNEL);
+               if (!urb)
+                       return -ENOMEM;
+
+               /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
+               usb_fill_bulk_urb (urb, stv680->udev,
+                                  usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
+                                  stv680->sbuf[i].data, stv680->rawbufsize,
+                                  stv680_video_irq, stv680);
+               stv680->urb[i] = urb;
+               err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
+               if (err)
+                       PDEBUG (0, "STV(e): urb burned down in start stream");
+       }                       /* i STV680_NUMSBUF */
+
+       stv680->framecount = 0;
+       return 0;
+}
+
+static int stv680_stop_stream (struct usb_stv *stv680)
+{
+       int i;
+
+       if (!stv680->streaming || !stv680->udev)
+               return 1;
+
+       stv680->streaming = 0;
+
+       for (i = 0; i < STV680_NUMSBUF; i++)
+               if (stv680->urb[i]) {
+                       usb_kill_urb (stv680->urb[i]);
+                       usb_free_urb (stv680->urb[i]);
+                       stv680->urb[i] = NULL;
+                       kfree(stv680->sbuf[i].data);
+               }
+       for (i = 0; i < STV680_NUMSCRATCH; i++) {
+               kfree(stv680->scratch[i].data);
+               stv680->scratch[i].data = NULL;
+       }
+
+       return 0;
+}
+
+static int stv680_set_size (struct usb_stv *stv680, int width, int height)
+{
+       int wasstreaming = stv680->streaming;
+
+       /* Check to see if we need to change */
+       if ((stv680->vwidth == width) && (stv680->vheight == height))
+               return 0;
+
+       PDEBUG (1, "STV(i): size request for %i x %i", width, height);
+       /* Check for a valid mode */
+       if ((!width || !height) || ((width & 1) || (height & 1))) {
+               PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+               return 1;
+       }
+
+       if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
+               width = stv680->maxwidth / 2;
+               height = stv680->maxheight / 2;
+       } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
+               width = 160;
+               height = 120;
+       } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
+               width = 176;
+               height = 144;
+       } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
+               width = 320;
+               height = 240;
+       } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
+               width = 352;
+               height = 288;
+       } else {
+               PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+               return 1;
+       }
+
+       /* Stop a current stream and start it again at the new size */
+       if (wasstreaming)
+               stv680_stop_stream (stv680);
+       stv680->vwidth = width;
+       stv680->vheight = height;
+       PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
+       if (wasstreaming)
+               stv680_start_stream (stv680);
+
+       return 0;
+}
+
+/**********************************************************************
+ * Video Decoding
+ **********************************************************************/
+
+/*******  routines from the pencam program; hey, they work!  ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org>
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define AD(x, y, w) (((y)*(w)+(x))*3)
+
+static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
+{
+       int x, y, i;
+       int w = stv680->cwidth;
+       int vw = stv680->cwidth, vh = stv680->cheight;
+       unsigned int p = 0;
+       int colour = 0, bayer = 0;
+       unsigned char *raw = buffer->data;
+       struct stv680_frame *frame = &stv680->frame[stv680->curframe];
+       unsigned char *output = frame->data;
+       unsigned char *temp = frame->data;
+       int offset = buffer->offset;
+
+       if (frame->curpix == 0) {
+               if (frame->grabstate == FRAME_READY) {
+                       frame->grabstate = FRAME_GRABBING;
+               }
+       }
+       if (offset != frame->curpix) {  /* Regard frame as lost :( */
+               frame->curpix = 0;
+               stv680->error++;
+               return;
+       }
+
+       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
+               vw = 320;
+               vh = 240;
+       }
+       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
+               vw = 352;
+               vh = 288;
+       }
+
+       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
+
+       for (y = 0; y < vh; y++) {
+               for (x = 0; x < vw; x++) {
+                       if (x & 1)
+                               p = *(raw + y * w + (x >> 1));
+                       else
+                               p = *(raw + y * w + (x >> 1) + (w >> 1));
+
+                       if (y & 1)
+                               bayer = 2;
+                       else
+                               bayer = 0;
+                       if (x & 1)
+                               bayer++;
+
+                       switch (bayer) {
+                       case 0:
+                       case 3:
+                               colour = 1;
+                               break;
+                       case 1:
+                               colour = 0;
+                               break;
+                       case 2:
+                               colour = 2;
+                               break;
+                       }
+                       i = (y * vw + x) * 3;
+                       *(output + i + colour) = (unsigned char) p;
+               }               /* for x */
+
+       }                       /* for y */
+
+       /****** gamma correction plus hardcoded white balance */
+       /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
+          Correction values red[], green[], blue[], are generated by
+          (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
+          White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
+          converted to unsigned char. Values are in stv680.h  */
+
+       for (y = 0; y < vh; y++) {
+               for (x = 0; x < vw; x++) {
+                       i = (y * vw + x) * 3;
+                       *(output + i) = red[*(output + i)];
+                       *(output + i + 1) = green[*(output + i + 1)];
+                       *(output + i + 2) = blue[*(output + i + 2)];
+               }
+       }
+
+       /******  bayer demosaic  ******/
+       for (y = 1; y < (vh - 1); y++) {
+               for (x = 1; x < (vw - 1); x++) {        /* work out pixel type */
+                       if (y & 1)
+                               bayer = 0;
+                       else
+                               bayer = 2;
+                       if (!(x & 1))
+                               bayer++;
+
+                       switch (bayer) {
+                       case 0: /* green. blue lr, red tb */
+                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
+                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
+                               break;
+
+                       case 1: /* blue. green lrtb, red diagonals */
+                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
+                               break;
+
+                       case 2: /* red. green lrtb, blue diagonals */
+                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
+                               break;
+
+                       case 3: /* green. red lr, blue tb */
+                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
+                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
+                               break;
+                       }       /* switch */
+               }               /* for x */
+       }                       /* for y  - end demosaic  */
+
+       /* fix top and bottom row, left and right side */
+       i = vw * 3;
+       memcpy (output, (output + i), i);
+       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+       for (y = 0; y < vh; y++) {
+               i = y * vw * 3;
+               memcpy ((output + i), (output + i + 3), 3);
+               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+       }
+
+       /*  process all raw data, then trim to size if necessary */
+       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+               i = 0;
+               for (y = 0; y < vh; y++) {
+                       if (!(y & 1)) {
+                               for (x = 0; x < vw; x++) {
+                                       p = (y * vw + x) * 3;
+                                       if (!(x & 1)) {
+                                               *(output + i) = *(output + p);
+                                               *(output + i + 1) = *(output + p + 1);
+                                               *(output + i + 2) = *(output + p + 2);
+                                               i += 3;
+                                       }
+                               }  /* for x */
+                       }
+               }  /* for y */
+       }
+       /* reset to proper width */
+       if ((stv680->vwidth == 160)) {
+               vw = 160;
+               vh = 120;
+       }
+       if ((stv680->vwidth == 176)) {
+               vw = 176;
+               vh = 144;
+       }
+
+       /* output is RGB; some programs want BGR  */
+       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+       /* swapRGB_on=-1, never swap */
+       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
+               for (y = 0; y < vh; y++) {
+                       for (x = 0; x < vw; x++) {
+                               i = (y * vw + x) * 3;
+                               *(temp) = *(output + i);
+                               *(output + i) = *(output + i + 2);
+                               *(output + i + 2) = *(temp);
+                       }
+               }
+       }
+       /* brightness */
+       if (stv680->chgbright == 1) {
+               if (stv680->brightness >= 32767) {
+                       p = (stv680->brightness - 32767) / 256;
+                       for (x = 0; x < (vw * vh * 3); x++) {
+                               if ((*(output + x) + (unsigned char) p) > 255)
+                                       *(output + x) = 255;
+                               else
+                                       *(output + x) += (unsigned char) p;
+                       }       /* for */
+               } else {
+                       p = (32767 - stv680->brightness) / 256;
+                       for (x = 0; x < (vw * vh * 3); x++) {
+                               if ((unsigned char) p > *(output + x))
+                                       *(output + x) = 0;
+                               else
+                                       *(output + x) -= (unsigned char) p;
+                       }       /* for */
+               }               /* else */
+       }
+       /* if */
+       frame->curpix = 0;
+       frame->curlinepix = 0;
+       frame->grabstate = FRAME_DONE;
+       stv680->framecount++;
+       stv680->readcount++;
+       if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+               stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
+       }
+
+}                              /* bayer_unshuffle */
+
+/*******  end routines from the pencam program  *********/
+
+static int stv680_newframe (struct usb_stv *stv680, int framenr)
+{
+       int errors = 0;
+
+       while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
+               if (!stv680->frame[framenr].curpix) {
+                       errors++;
+               }
+               wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
+
+               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+                       stv680->nullpackets = 0;
+                       PDEBUG (2, "STV(i): too many null length packets, restarting capture");
+                       stv680_stop_stream (stv680);
+                       stv680_start_stream (stv680);
+               } else {
+                       if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
+                               stv680->frame[framenr].grabstate = FRAME_ERROR;
+                               PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
+                               return -EIO;
+                       }
+                       stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
+
+                       bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
+
+                       stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
+                       stv680->scratch_use++;
+                       if (stv680->scratch_use >= STV680_NUMSCRATCH)
+                               stv680->scratch_use = 0;
+                       if (errors > STV680_MAX_ERRORS) {
+                               errors = 0;
+                               PDEBUG (2, "STV(i): too many errors, restarting capture");
+                               stv680_stop_stream (stv680);
+                               stv680_start_stream (stv680);
+                       }
+               }               /* else */
+       }                       /* while */
+       return 0;
+}
+
+/*********************************************************************
+ * Video4Linux
+ *********************************************************************/
+
+static int stv_open (struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       int err = 0;
+
+       /* we are called with the BKL held */
+       stv680->user = 1;
+       err = stv_init (stv680);        /* main initialization routine for camera */
+
+       if (err >= 0) {
+               stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
+               if (!stv680->fbuf) {
+                       PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
+                       err = -ENOMEM;
+               }
+               file->private_data = dev;
+       }
+       if (err)
+               stv680->user = 0;
+
+       return err;
+}
+
+static int stv_close (struct inode *inode, struct file *file)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < STV680_NUMFRAMES; i++)
+               stv680->frame[i].grabstate = FRAME_UNUSED;
+       if (stv680->streaming)
+               stv680_stop_stream (stv680);
+
+       if ((i = stv_stop_video (stv680)) < 0)
+               PDEBUG (1, "STV(e): stop_video failed in stv_close");
+
+       rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
+       stv680->user = 0;
+
+       if (stv680->removed) {
+               kfree(stv680);
+               stv680 = NULL;
+               PDEBUG (0, "STV(i): device unregistered");
+       }
+       file->private_data = NULL;
+       return 0;
+}
+
+static int stv680_do_ioctl (struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_stv *stv680 = video_get_drvdata(vdev);
+
+       if (!stv680->udev)
+               return -EIO;
+
+       switch (cmd) {
+       case VIDIOCGCAP:{
+                       struct video_capability *b = arg;
+
+                       strcpy (b->name, stv680->camera_name);
+                       b->type = VID_TYPE_CAPTURE;
+                       b->channels = 1;
+                       b->audios = 0;
+                       b->maxwidth = stv680->maxwidth;
+                       b->maxheight = stv680->maxheight;
+                       b->minwidth = stv680->maxwidth / 2;
+                       b->minheight = stv680->maxheight / 2;
+                       return 0;
+               }
+       case VIDIOCGCHAN:{
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy (v->name, "STV Camera");
+                       return 0;
+               }
+       case VIDIOCSCHAN:{
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+       case VIDIOCGPICT:{
+                       struct video_picture *p = arg;
+
+                       stv680_get_pict (stv680, p);
+                       return 0;
+               }
+       case VIDIOCSPICT:{
+                       struct video_picture *p = arg;
+
+                       if (stv680_set_pict (stv680, p))
+                               return -EINVAL;
+                       return 0;
+               }
+       case VIDIOCSWIN:{
+                       struct video_window *vw = arg;
+
+                       if (vw->flags)
+                               return -EINVAL;
+                       if (vw->clipcount)
+                               return -EINVAL;
+                       if (vw->width != stv680->vwidth) {
+                               if (stv680_set_size (stv680, vw->width, vw->height)) {
+                                       PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
+                                       return -EINVAL;
+                               }
+                       }
+                       return 0;
+               }
+       case VIDIOCGWIN:{
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;      /* FIXME */
+                       vw->y = 0;
+                       vw->chromakey = 0;
+                       vw->flags = 0;
+                       vw->clipcount = 0;
+                       vw->width = stv680->vwidth;
+                       vw->height = stv680->vheight;
+                       return 0;
+               }
+       case VIDIOCGMBUF:{
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset (vm, 0, sizeof (*vm));
+                       vm->size = STV680_NUMFRAMES * stv680->maxframesize;
+                       vm->frames = STV680_NUMFRAMES;
+                       for (i = 0; i < STV680_NUMFRAMES; i++)
+                               vm->offsets[i] = stv680->maxframesize * i;
+                       return 0;
+               }
+       case VIDIOCMCAPTURE:{
+                       struct video_mmap *vm = arg;
+
+                       if (vm->format != STV_VIDEO_PALETTE) {
+                               PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
+                                       vm->format, STV_VIDEO_PALETTE);
+                               if ((vm->format == 3) && (swapRGB_on == 0))  {
+                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
+                                       /* this may fix those apps (e.g., xawtv) that want BGR */
+                                       swapRGB = 1;
+                               }
+                               return -EINVAL;
+                       }
+                       if (vm->frame >= STV680_NUMFRAMES) {
+                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
+                               return -EINVAL;
+                       }
+                       if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
+                           || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
+                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+                                       stv680->frame[vm->frame].grabstate);
+                               return -EBUSY;
+                       }
+                       /* Is this according to the v4l spec??? */
+                       if (stv680->vwidth != vm->width) {
+                               if (stv680_set_size (stv680, vm->width, vm->height)) {
+                                       PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
+                                       return -EINVAL;
+                               }
+                       }
+                       stv680->frame[vm->frame].grabstate = FRAME_READY;
+
+                       if (!stv680->streaming)
+                               stv680_start_stream (stv680);
+
+                       return 0;
+               }
+       case VIDIOCSYNC:{
+                       int *frame = arg;
+                       int ret = 0;
+
+                       if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
+                               PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
+                               return -EINVAL;
+                       }
+                       ret = stv680_newframe (stv680, *frame);
+                       stv680->frame[*frame].grabstate = FRAME_UNUSED;
+                       return ret;
+               }
+       case VIDIOCGFBUF:{
+                       struct video_buffer *vb = arg;
+
+                       memset (vb, 0, sizeof (*vb));
+                       return 0;
+               }
+       case VIDIOCKEY:
+               return 0;
+       case VIDIOCCAPTURE:
+               {
+                       PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
+                       return -EINVAL;
+               }
+       case VIDIOCSFBUF:
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return -EINVAL;
+       default:
+               return -ENOIOCTLCMD;
+       }                       /* end switch */
+
+       return 0;
+}
+
+static int stv680_ioctl(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl);
+}
+
+static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       mutex_lock(&stv680->lock);
+
+       if (stv680->udev == NULL) {
+               mutex_unlock(&stv680->lock);
+               return -EIO;
+       }
+       if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
+                   & ~(PAGE_SIZE - 1))) {
+               mutex_unlock(&stv680->lock);
+               return -EINVAL;
+       }
+       pos = (unsigned long) stv680->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       mutex_unlock(&stv680->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       mutex_unlock(&stv680->lock);
+
+       return 0;
+}
+
+static ssize_t stv680_read (struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct video_device *dev = file->private_data;
+       unsigned long int realcount = count;
+       int ret = 0;
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       unsigned long int i;
+
+       if (STV680_NUMFRAMES != 2) {
+               PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
+               return -1;
+       }
+       if (stv680->udev == NULL)
+               return -EIO;
+       if (realcount > (stv680->vwidth * stv680->vheight * 3))
+               realcount = stv680->vwidth * stv680->vheight * 3;
+
+       /* Shouldn't happen: */
+       if (stv680->frame[0].grabstate == FRAME_GRABBING) {
+               PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
+               return -EBUSY;
+       }
+       stv680->frame[0].grabstate = FRAME_READY;
+       stv680->frame[1].grabstate = FRAME_UNUSED;
+       stv680->curframe = 0;
+
+       if (!stv680->streaming)
+               stv680_start_stream (stv680);
+
+       if (!stv680->streaming) {
+               ret = stv680_newframe (stv680, 0);      /* ret should = 0 */
+       }
+
+       ret = stv680_newframe (stv680, 0);
+
+       if (!ret) {
+               if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
+                       PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
+                       return -EFAULT;
+               }
+       } else {
+               realcount = ret;
+       }
+       stv680->frame[0].grabstate = FRAME_UNUSED;
+       return realcount;
+}                              /* stv680_read */
+
+static struct file_operations stv680_fops = {
+       .owner =        THIS_MODULE,
+       .open =         stv_open,
+       .release =      stv_close,
+       .read =         stv680_read,
+       .mmap =         stv680_mmap,
+       .ioctl =        stv680_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+static struct video_device stv680_template = {
+       .owner =        THIS_MODULE,
+       .name =         "STV0680 USB camera",
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_SE401,
+       .fops =         &stv680_fops,
+       .release =      video_device_release,
+       .minor =        -1,
+};
+
+static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface;
+       struct usb_stv *stv680 = NULL;
+       char *camera_name = NULL;
+       int retval = 0;
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1) {
+               PDEBUG (0, "STV(e): Number of Configurations != 1");
+               return -ENODEV;
+       }
+
+       interface = &intf->altsetting[0];
+       /* Is it a STV680? */
+       if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
+           (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
+               camera_name = "STV0680";
+               PDEBUG (0, "STV(i): STV0680 camera found.");
+       } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
+                  (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
+               camera_name = "Creative WebCam Go Mini";
+               PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
+       } else {
+               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
+               PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
+               retval = -ENODEV;
+               goto error;
+       }
+       /* We found one */
+       if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+               PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       stv680->udev = dev;
+       stv680->camera_name = camera_name;
+
+       stv680->vdev = video_device_alloc();
+       if (!stv680->vdev) {
+               retval = -ENOMEM;
+               goto error;
+       }
+       memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
+       stv680->vdev->dev = &intf->dev;
+       video_set_drvdata(stv680->vdev, stv680);
+
+       memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
+       init_waitqueue_head (&stv680->wq);
+       mutex_init (&stv680->lock);
+       wmb ();
+
+       if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               PDEBUG (0, "STV(e): video_register_device failed");
+               retval = -EIO;
+               goto error_vdev;
+       }
+       PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
+
+       usb_set_intfdata (intf, stv680);
+       stv680_create_sysfs_files(stv680->vdev);
+       return 0;
+
+error_vdev:
+       video_device_release(stv680->vdev);
+error:
+       kfree(stv680);
+       return retval;
+}
+
+static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
+{
+       int i;
+
+       stv680->udev = NULL;
+       stv680->frame[0].grabstate = FRAME_ERROR;
+       stv680->frame[1].grabstate = FRAME_ERROR;
+       stv680->streaming = 0;
+
+       wake_up_interruptible (&stv680->wq);
+
+       for (i = 0; i < STV680_NUMSBUF; i++)
+               if (stv680->urb[i]) {
+                       usb_kill_urb (stv680->urb[i]);
+                       usb_free_urb (stv680->urb[i]);
+                       stv680->urb[i] = NULL;
+                       kfree(stv680->sbuf[i].data);
+               }
+       for (i = 0; i < STV680_NUMSCRATCH; i++)
+               kfree(stv680->scratch[i].data);
+       PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
+
+       /* Free the memory */
+       kfree(stv680);
+}
+
+static void stv680_disconnect (struct usb_interface *intf)
+{
+       struct usb_stv *stv680 = usb_get_intfdata (intf);
+
+       usb_set_intfdata (intf, NULL);
+
+       if (stv680) {
+               /* We don't want people trying to open up the device */
+               if (stv680->vdev) {
+                       stv680_remove_sysfs_files(stv680->vdev);
+                       video_unregister_device(stv680->vdev);
+                       stv680->vdev = NULL;
+               }
+               if (!stv680->user) {
+                       usb_stv680_remove_disconnected (stv680);
+               } else {
+                       stv680->removed = 1;
+               }
+       }
+}
+
+static struct usb_driver stv680_driver = {
+       .name =         "stv680",
+       .probe =        stv680_probe,
+       .disconnect =   stv680_disconnect,
+       .id_table =     device_table
+};
+
+/********************************************************************
+ *  Module routines
+ ********************************************************************/
+
+static int __init usb_stv680_init (void)
+{
+       if (usb_register (&stv680_driver) < 0) {
+               PDEBUG (0, "STV(e): Could not setup STV0680 driver");
+               return -1;
+       }
+       PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
+
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+}
+
+static void __exit usb_stv680_exit (void)
+{
+       usb_deregister (&stv680_driver);
+       PDEBUG (0, "STV(i): driver deregistered");
+}
+
+module_init (usb_stv680_init);
+module_exit (usb_stv680_exit);
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h
new file mode 100644 (file)
index 0000000..a08f1b0
--- /dev/null
@@ -0,0 +1,227 @@
+/****************************************************************************
+ *
+ *  Filename: stv680.h
+ *
+ *  Description:
+ *     This is a USB driver for STV0680 based usb video cameras.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+/* size of usb transfers */
+#define STV680_PACKETSIZE      4096
+
+/* number of queued bulk transfers to use, may have problems if > 1 */
+#define STV680_NUMSBUF         1
+
+/* number of frames supported by the v4l part */
+#define STV680_NUMFRAMES       2
+
+/* scratch buffers for passing data to the decoders: 2 or 4 are good */
+#define STV680_NUMSCRATCH      2
+
+/* number of nul sized packets to receive before kicking the camera */
+#define STV680_MAX_NULLPACKETS 200
+
+/* number of decoding errors before kicking the camera */
+#define STV680_MAX_ERRORS      100
+
+#define USB_PENCAM_VENDOR_ID   0x0553
+#define USB_PENCAM_PRODUCT_ID  0x0202
+
+#define USB_CREATIVEGOMINI_VENDOR_ID   0x041e
+#define USB_CREATIVEGOMINI_PRODUCT_ID  0x4007
+
+#define PENCAM_TIMEOUT          1000
+/* fmt 4 */
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
+
+static struct usb_device_id device_table[] = {
+       {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+       {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
+       {}
+};
+MODULE_DEVICE_TABLE (usb, device_table);
+
+struct stv680_sbuf {
+       unsigned char *data;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+enum {
+       BUFFER_UNUSED,
+       BUFFER_READY,
+       BUFFER_BUSY,
+       BUFFER_DONE,
+};
+
+/* raw camera data <- sbuf (urb transfer buf) */
+struct stv680_scratch {
+       unsigned char *data;
+       volatile int state;
+       int offset;
+       int length;
+};
+
+/* processed data for display ends up here, after bayer */
+struct stv680_frame {
+       unsigned char *data;    /* Frame buffer */
+       volatile int grabstate; /* State of grabbing */
+       unsigned char *curline;
+       int curlinepix;
+       int curpix;
+};
+
+/* this is almost the video structure uvd_t, with extra parameters for stv */
+struct usb_stv {
+       struct video_device *vdev;
+
+       struct usb_device *udev;
+
+       unsigned char bulk_in_endpointAddr;     /* __u8  the address of the bulk in endpoint */
+       char *camera_name;
+
+       unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
+       int SupportedModes;
+       int CIF;
+       int VGA;
+       int QVGA;
+       int cwidth;             /* camera width */
+       int cheight;            /* camera height */
+       int maxwidth;           /* max video width */
+       int maxheight;          /* max video height */
+       int vwidth;             /* current width for video window */
+       int vheight;            /* current height for video window */
+       unsigned long int rawbufsize;
+       unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
+
+       int origGain;
+       int origMode;           /* original camera mode */
+
+       struct mutex lock;      /* to lock the structure */
+       int user;               /* user count for exclusive use */
+       int removed;            /* device disconnected */
+       int streaming;          /* Are we streaming video? */
+       char *fbuf;             /* Videodev buffer area */
+       struct urb *urb[STV680_NUMSBUF];        /* # of queued bulk transfers */
+       int curframe;           /* Current receiving frame */
+       struct stv680_frame frame[STV680_NUMFRAMES];    /* # frames supported by v4l part */
+       int readcount;
+       int framecount;
+       int error;
+       int dropped;
+       int scratch_next;
+       int scratch_use;
+       int scratch_overflow;
+       struct stv680_scratch scratch[STV680_NUMSCRATCH];       /* for decoders */
+       struct stv680_sbuf sbuf[STV680_NUMSBUF];
+
+       unsigned int brightness;
+       unsigned int chgbright;
+       unsigned int whiteness;
+       unsigned int colour;
+       unsigned int contrast;
+       unsigned int hue;
+       unsigned int palette;
+       unsigned int depth;     /* rgb24 in bits */
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int nullpackets;
+};
+
+
+static const unsigned char red[256] = {
+       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42,
+       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69,
+       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87,
+       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101,
+       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134,
+       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143,
+       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151,
+       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
+       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166,
+       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173,
+       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179,
+       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186,
+       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192,
+       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197,
+       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204,
+       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209,
+       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
+       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219,
+       220, 220, 221, 221
+};
+
+static const unsigned char green[256] = {
+       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
+       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
+       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
+       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
+       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
+       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
+       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
+       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
+       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
+       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
+       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
+       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
+       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
+       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
+       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
+       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
+       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
+       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
+       245, 245, 246, 246
+};
+
+static const unsigned char blue[256] = {
+       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51,
+       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84,
+       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106,
+       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124,
+       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138,
+       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151,
+       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163,
+       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174,
+       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184,
+       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194,
+       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203,
+       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212,
+       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220,
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
+       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235,
+       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242,
+       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249,
+       249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255,
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+       255, 255, 255, 255
+};
index fc3d5824efffd330a828e64d04c5e58460ed118e..78e043ac9ea0e39fa2195d0b9ddba060db56361b 100644 (file)
@@ -48,9 +48,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
-#include "bttv.h"
-#include <media/audiochip.h>
 #include <media/v4l2-common.h>
+#include <media/i2c-addr.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -71,7 +70,7 @@ module_param(maxvol, int, S_IRUGO | S_IWUSR);
 
 /* Address to scan (I2C address of this chip) */
 static unsigned short normal_i2c[] = {
-       I2C_TDA7432 >> 1,
+       I2C_ADDR_TDA7432 >> 1,
        I2C_CLIENT_END,
 };
 I2C_CLIENT_INSMOD;
index 0243700f58ae28579008a9309e68af434d857946..ef494febb5e4f7996c9752861cde4134c6c74c80 100644 (file)
@@ -35,7 +35,7 @@ static int debug = 0;         /* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define dprintk(args...) \
-            do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+           do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
 
 #define        SWITCH          0x00
 #define        LEVEL_ADJUST    0x02
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define        TEST            0x04
 
 /* addresses to scan, found only at 0x42 (7-Bit) */
-static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
 
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
index 28021053bd097f64d389503d108967ad337e43f0..7da8432cdca7378ea1c4879c0e7db27213753d75 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __INCLUDED_TDA9840__
 #define __INCLUDED_TDA9840__
 
-#define        I2C_TDA9840             0x42
+#define        I2C_ADDR_TDA9840                0x42
 
 #define TDA9840_DETECT         _IOR('v',1,int)
 /* return values for TDA9840_DETCT */
index ef98c49822507f63d5ffbf710890541cdc8c2e6c..103ccb91929260353df41e36a2e0be86ae882dc2 100644 (file)
 #include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
 
-#include "bttv.h"
-#include <media/audiochip.h>
+
+#include <media/i2c-addr.h>
 
 static int debug; /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_LICENSE("GPL");
 
-
 /* Addresses to scan */
 static unsigned short normal_i2c[] =  {
-    I2C_TDA9875 >> 1,
+    I2C_ADDR_TDA9875 >> 1,
     I2C_CLIENT_END
 };
 I2C_CLIENT_INSMOD;
 
 /* This is a superset of the TDA9875 */
 struct tda9875 {
-       int mode;
        int rvol, lvol;
        int bass, treble;
        struct i2c_client c;
@@ -197,7 +195,6 @@ static void do_tda9875_init(struct i2c_client *client)
 
        tda9875_write(client, TDA9875_MUT, 0xcc );   /* General mute  */
 
-       t->mode=AUDIO_UNMUTE;
        t->lvol=t->rvol =0;     /* 0dB */
        t->bass=0;                      /* 0dB */
        t->treble=0;            /* 0dB */
index 774ed0dbc56d85a3ff10a536f8cd6c47e4714093..523df0b8cc63c387e4446a41a91fe62d8e392d3a 100644 (file)
@@ -37,7 +37,7 @@ static int debug = 0;         /* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define dprintk(args...) \
-            do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+           do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
 
 #define TEA6415C_NUM_INPUTS    8
 #define TEA6415C_NUM_OUTPUTS   6
index ad7d2872cfbfb33c3b42e20d63ee74f24a4e0b6c..e0ff811fab6f3e69a69af355e287f4d6db29c92e 100644 (file)
@@ -37,10 +37,10 @@ static int debug = 0;               /* insmod parameter */
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 #define dprintk(args...) \
-            do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+           do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
 
 /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
-static unsigned short normal_i2c[] = { I2C_TEA6420_1, I2C_TEA6420_2, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
 
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
index ea664df15ad4f8bdd8446f3bd7e5f6b7bf0b79d5..5ef7c18e0c5404e08d0a4a840f050b15db33c6e6 100644 (file)
@@ -2,8 +2,8 @@
 #define __INCLUDED_TEA6420__
 
 /* possible addresses */
-#define        I2C_TEA6420_1           0x4c
-#define        I2C_TEA6420_2           0x4d
+#define        I2C_ADDR_TEA6420_1              0x4c
+#define        I2C_ADDR_TEA6420_2              0x4d
 
 struct tea6420_multiplex
 {
index c4a78e7a5a58bf3206ccae4f69ee9d7ba3d98580..74ab48c09c6a448a745f3469ae08cdc9c1adf373 100644 (file)
@@ -5,7 +5,7 @@
  *
  * The SAB3036 is just about different enough from the chips that
  * tuner.c copes with to make it not worth the effort to crowbar
- * the support into that file.  So instead we have a separate driver. 
+ * the support into that file.  So instead we have a separate driver.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -56,15 +56,15 @@ tuner_getstatus (struct i2c_client *c)
 
 #define TUNER_FL        0x80
 
-static int 
+static int
 tuner_islocked (struct i2c_client *c)
 {
-        return (tuner_getstatus(c) & TUNER_FL);
+       return (tuner_getstatus(c) & TUNER_FL);
 }
 
 /* ---------------------------------------------------------------------- */
 
-static void 
+static void
 set_tv_freq(struct i2c_client *c, int freq)
 {
        u16 div = ((freq * 20) / 16);
@@ -73,26 +73,26 @@ set_tv_freq(struct i2c_client *c, int freq)
 
        if (debug)
                printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div);
-       
+
        /* Select high tuning current */
        buffer[0] = 0x29;
        buffer[1] = 0x3e;
 
        if (i2c_master_send(c, buffer, 2) != 2)
                printk("tuner: i2c i/o error 1\n");
-       
+
        buffer[0] = 0x80 | ((div>>8) & 0x7f);
        buffer[1] = div & 0xff;
 
        if (i2c_master_send(c, buffer, 2) != 2)
                printk("tuner: i2c i/o error 2\n");
-       
+
        while (!tuner_islocked(c) && time_before(jiffies, give_up))
                schedule();
-              
+
        if (!tuner_islocked(c))
                printk(KERN_WARNING "tuner: failed to achieve PLL lock\n");
-       
+
        /* Select low tuning current and engage AFC */
        buffer[0] = 0x29;
        buffer[1] = 0xb2;
@@ -106,7 +106,7 @@ set_tv_freq(struct i2c_client *c, int freq)
 
 /* ---------------------------------------------------------------------- */
 
-static int 
+static int
 tuner_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 };
@@ -116,18 +116,18 @@ tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        if (this_adap > 0)
                return -1;
        this_adap++;
-       
-        client_template.adapter = adap;
-        client_template.addr = addr;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
 
        client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-        if (client == NULL)
-                return -ENOMEM;
-        memcpy(client, &client_template, sizeof(struct i2c_client));
+       if (client == NULL)
+               return -ENOMEM;
+       memcpy(client, &client_template, sizeof(struct i2c_client));
 
        printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client));
 
-        i2c_attach_client(client);
+       i2c_attach_client(client);
 
        if (i2c_master_send(client, buffer, 2) != 2)
                printk("tuner: i2c i/o error 1\n");
@@ -138,30 +138,30 @@ tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        return 0;
 }
 
-static int 
+static int
 tuner_detach(struct i2c_client *c)
 {
        return 0;
 }
 
-static int 
+static int
 tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        int *iarg = (int*)arg;
 
-       switch (cmd) 
+       switch (cmd)
        {
                case VIDIOCSFREQ:
                        set_tv_freq(client, *iarg);
                        break;
-           
+
                default:
                        return -EINVAL;
        }
        return 0;
 }
 
-static int 
+static int
 tuner_probe(struct i2c_adapter *adap)
 {
        this_adap = 0;
@@ -172,8 +172,8 @@ tuner_probe(struct i2c_adapter *adap)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver 
-i2c_driver_tuner = 
+static struct i2c_driver
+i2c_driver_tuner =
 {
        .driver = {
                .name   =       "sab3036",
@@ -186,7 +186,7 @@ i2c_driver_tuner =
 
 static struct i2c_client client_template =
 {
-        .driver                = &i2c_driver_tuner,
+       .driver         = &i2c_driver_tuner,
        .name           = "SAB3036",
 };
 
index 32e1849441fb45947bd5b2be561bed1e6950d048..df195c905366c774d16bdfff47987d2523cff297 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
-#include <media/audiochip.h>
 
 #define UNSET (-1U)
 
index 4efb01bb44ac1cdce5212c69caa745116c3a7a73..356bff455ad18109080a132937fb7e3330f07289 100644 (file)
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 
-#include <media/audiochip.h>
+#include <media/tvaudio.h>
 #include <media/v4l2-common.h>
 
-#include "tvaudio.h"
+#include <media/i2c-addr.h>
 
 /* ---------------------------------------------------------------------- */
 /* insmod args                                                            */
@@ -102,7 +102,7 @@ struct CHIPDESC {
 
        /* input switch register + values for v4l inputs */
        int  inputreg;
-       int  inputmap[8];
+       int  inputmap[4];
        int  inputmute;
        int  inputmask;
 };
@@ -119,9 +119,10 @@ struct CHIPSTATE {
        audiocmd   shadow;
 
        /* current settings */
-       __u16 left,right,treble,bass,mode;
+       __u16 left,right,treble,bass,muted,mode;
        int prevmode;
        int radio;
+       int input;
 
        /* thread */
        pid_t                tpid;
@@ -137,14 +138,14 @@ struct CHIPSTATE {
 /* i2c addresses                                                          */
 
 static unsigned short normal_i2c[] = {
-       I2C_TDA8425   >> 1,
-       I2C_TEA6300   >> 1,
-       I2C_TEA6420   >> 1,
-       I2C_TDA9840   >> 1,
-       I2C_TDA985x_L >> 1,
-       I2C_TDA985x_H >> 1,
-       I2C_TDA9874   >> 1,
-       I2C_PIC16C54  >> 1,
+       I2C_ADDR_TDA8425   >> 1,
+       I2C_ADDR_TEA6300   >> 1,
+       I2C_ADDR_TEA6420   >> 1,
+       I2C_ADDR_TDA9840   >> 1,
+       I2C_ADDR_TDA985x_L >> 1,
+       I2C_ADDR_TDA985x_H >> 1,
+       I2C_ADDR_TDA9874   >> 1,
+       I2C_ADDR_PIC16C54  >> 1,
        I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
@@ -1101,9 +1102,8 @@ static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 static int tda8425_initialize(struct CHIPSTATE *chip)
 {
        struct CHIPDESC *desc = chiplist + chip->type;
-       int inputmap[8] = { /* tuner    */ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
-                           /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF,
-                           /* off      */ TDA8425_S1_OFF, /* on     */ TDA8425_S1_CH2};
+       int inputmap[4] = { /* tuner    */ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
+                           /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
 
        if (chip->c.adapter->id == I2C_HW_B_RIVA) {
                memcpy (desc->inputmap, inputmap, sizeof (inputmap));
@@ -1269,8 +1269,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "tda9840",
                .id         = I2C_DRIVERID_TDA9840,
                .insmodopt  = &tda9840,
-               .addr_lo    = I2C_TDA9840 >> 1,
-               .addr_hi    = I2C_TDA9840 >> 1,
+               .addr_lo    = I2C_ADDR_TDA9840 >> 1,
+               .addr_hi    = I2C_ADDR_TDA9840 >> 1,
                .registers  = 5,
 
                .checkit    = tda9840_checkit,
@@ -1286,8 +1286,8 @@ static struct CHIPDESC chiplist[] = {
                .id         = I2C_DRIVERID_TDA9873,
                .checkit    = tda9873_checkit,
                .insmodopt  = &tda9873,
-               .addr_lo    = I2C_TDA985x_L >> 1,
-               .addr_hi    = I2C_TDA985x_H >> 1,
+               .addr_lo    = I2C_ADDR_TDA985x_L >> 1,
+               .addr_hi    = I2C_ADDR_TDA985x_H >> 1,
                .registers  = 3,
                .flags      = CHIP_HAS_INPUTSEL,
 
@@ -1298,7 +1298,7 @@ static struct CHIPDESC chiplist[] = {
                .init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
                .inputreg   = TDA9873_SW,
                .inputmute  = TDA9873_MUTE | TDA9873_AUTOMUTE,
-               .inputmap   = {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
+               .inputmap   = {0xa0, 0xa2, 0xa0, 0xa0},
                .inputmask  = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE,
 
        },
@@ -1308,8 +1308,8 @@ static struct CHIPDESC chiplist[] = {
                .checkit    = tda9874a_checkit,
                .initialize = tda9874a_initialize,
                .insmodopt  = &tda9874a,
-               .addr_lo    = I2C_TDA9874 >> 1,
-               .addr_hi    = I2C_TDA9874 >> 1,
+               .addr_lo    = I2C_ADDR_TDA9874 >> 1,
+               .addr_hi    = I2C_ADDR_TDA9874 >> 1,
 
                .getmode    = tda9874a_getmode,
                .setmode    = tda9874a_setmode,
@@ -1319,8 +1319,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "tda9850",
                .id         = I2C_DRIVERID_TDA9850,
                .insmodopt  = &tda9850,
-               .addr_lo    = I2C_TDA985x_L >> 1,
-               .addr_hi    = I2C_TDA985x_H >> 1,
+               .addr_lo    = I2C_ADDR_TDA985x_L >> 1,
+               .addr_hi    = I2C_ADDR_TDA985x_H >> 1,
                .registers  = 11,
 
                .getmode    = tda985x_getmode,
@@ -1332,8 +1332,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "tda9855",
                .id         = I2C_DRIVERID_TDA9855,
                .insmodopt  = &tda9855,
-               .addr_lo    = I2C_TDA985x_L >> 1,
-               .addr_hi    = I2C_TDA985x_H >> 1,
+               .addr_lo    = I2C_ADDR_TDA985x_L >> 1,
+               .addr_hi    = I2C_ADDR_TDA985x_H >> 1,
                .registers  = 11,
                .flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
 
@@ -1357,8 +1357,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "tea6300",
                .id         = I2C_DRIVERID_TEA6300,
                .insmodopt  = &tea6300,
-               .addr_lo    = I2C_TEA6300 >> 1,
-               .addr_hi    = I2C_TEA6300 >> 1,
+               .addr_lo    = I2C_ADDR_TEA6300 >> 1,
+               .addr_hi    = I2C_ADDR_TEA6300 >> 1,
                .registers  = 6,
                .flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
 
@@ -1379,8 +1379,8 @@ static struct CHIPDESC chiplist[] = {
                .id         = I2C_DRIVERID_TEA6300,
                .initialize = tea6320_initialize,
                .insmodopt  = &tea6320,
-               .addr_lo    = I2C_TEA6300 >> 1,
-               .addr_hi    = I2C_TEA6300 >> 1,
+               .addr_lo    = I2C_ADDR_TEA6300 >> 1,
+               .addr_hi    = I2C_ADDR_TEA6300 >> 1,
                .registers  = 8,
                .flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
 
@@ -1400,8 +1400,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "tea6420",
                .id         = I2C_DRIVERID_TEA6420,
                .insmodopt  = &tea6420,
-               .addr_lo    = I2C_TEA6420 >> 1,
-               .addr_hi    = I2C_TEA6420 >> 1,
+               .addr_lo    = I2C_ADDR_TEA6420 >> 1,
+               .addr_hi    = I2C_ADDR_TEA6420 >> 1,
                .registers  = 1,
                .flags      = CHIP_HAS_INPUTSEL,
 
@@ -1413,8 +1413,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "tda8425",
                .id         = I2C_DRIVERID_TDA8425,
                .insmodopt  = &tda8425,
-               .addr_lo    = I2C_TDA8425 >> 1,
-               .addr_hi    = I2C_TDA8425 >> 1,
+               .addr_lo    = I2C_ADDR_TDA8425 >> 1,
+               .addr_hi    = I2C_ADDR_TDA8425 >> 1,
                .registers  = 9,
                .flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
 
@@ -1437,8 +1437,8 @@ static struct CHIPDESC chiplist[] = {
                .name       = "pic16c54 (PV951)",
                .id         = I2C_DRIVERID_PIC16C54_PV9,
                .insmodopt  = &pic16c54,
-               .addr_lo    = I2C_PIC16C54 >> 1,
-               .addr_hi    = I2C_PIC16C54>> 1,
+               .addr_lo    = I2C_ADDR_PIC16C54 >> 1,
+               .addr_hi    = I2C_ADDR_PIC16C54>> 1,
                .registers  = 2,
                .flags      = CHIP_HAS_INPUTSEL,
 
@@ -1446,8 +1446,7 @@ static struct CHIPDESC chiplist[] = {
                .inputmap   = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
                             PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
                             PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
-                            PIC16C54_MISC_SND_MUTE,PIC16C54_MISC_SND_MUTE,
-                            PIC16C54_MISC_SND_NOTMUTE},
+                            PIC16C54_MISC_SND_MUTE},
                .inputmute  = PIC16C54_MISC_SND_MUTE,
        },
        {
@@ -1456,8 +1455,8 @@ static struct CHIPDESC chiplist[] = {
                /*.id         = I2C_DRIVERID_TA8874Z, */
                .checkit    = ta8874z_checkit,
                .insmodopt  = &ta8874z,
-               .addr_lo    = I2C_TDA9840 >> 1,
-               .addr_hi    = I2C_TDA9840 >> 1,
+               .addr_lo    = I2C_ADDR_TDA9840 >> 1,
+               .addr_hi    = I2C_ADDR_TDA9840 >> 1,
                .registers  = 2,
 
                .getmode    = ta8874z_getmode,
@@ -1583,28 +1582,40 @@ static int chip_detach(struct i2c_client *client)
        return 0;
 }
 
+static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
+{
+       struct CHIPDESC *desc = chiplist + chip->type;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value < 0 || ctrl->value >= 2)
+                       return -ERANGE;
+               chip->muted = ctrl->value;
+               if (chip->muted)
+                       chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
+               else
+                       chip_write_masked(chip,desc->inputreg,
+                                       desc->inputmap[chip->input],desc->inputmask);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
 /* ---------------------------------------------------------------------- */
 /* video4linux interface                                                  */
 
 static int chip_command(struct i2c_client *client,
                        unsigned int cmd, void *arg)
 {
-       __u16 *sarg = arg;
        struct CHIPSTATE *chip = i2c_get_clientdata(client);
        struct CHIPDESC  *desc = chiplist + chip->type;
 
        v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
 
        switch (cmd) {
-       case AUDC_SET_INPUT:
-               if (desc->flags & CHIP_HAS_INPUTSEL) {
-                       if (*sarg & 0x80)
-                               chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
-                       else
-                               chip_write_masked(chip,desc->inputreg,desc->inputmap[*sarg],desc->inputmask);
-               }
-               break;
-
        case AUDC_SET_RADIO:
                chip->radio = 1;
                chip->watch_stereo = 0;
@@ -1668,6 +1679,48 @@ static int chip_command(struct i2c_client *client,
                break;
        }
 
+       case VIDIOC_S_CTRL:
+               return tvaudio_set_ctrl(chip, arg);
+
+       case VIDIOC_INT_G_AUDIO_ROUTING:
+       {
+               struct v4l2_routing *rt = arg;
+
+               rt->input = chip->input;
+               rt->output = 0;
+               break;
+       }
+
+       case VIDIOC_INT_S_AUDIO_ROUTING:
+       {
+               struct v4l2_routing *rt = arg;
+
+               if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
+                               return -EINVAL;
+               /* There are four inputs: tuner, radio, extern and intern. */
+               chip->input = rt->input;
+               if (chip->muted)
+                       break;
+               chip_write_masked(chip, desc->inputreg,
+                               desc->inputmap[chip->input], desc->inputmask);
+               break;
+       }
+
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *sarg = arg;
+
+               if (!(desc->flags & CHIP_HAS_INPUTSEL) || sarg->index >= 4)
+                               return -EINVAL;
+               /* There are four inputs: tuner, radio, extern and intern. */
+               chip->input = sarg->index;
+               if (chip->muted)
+                       break;
+               chip_write_masked(chip, desc->inputreg,
+                               desc->inputmap[chip->input], desc->inputmask);
+               break;
+       }
+
        case VIDIOC_S_TUNER:
        {
                struct v4l2_tuner *vt = arg;
@@ -1680,6 +1733,7 @@ static int chip_command(struct i2c_client *client,
                        mode = VIDEO_SOUND_MONO;
                        break;
                case V4L2_TUNER_MODE_STEREO:
+               case V4L2_TUNER_MODE_LANG1_LANG2:
                        mode = VIDEO_SOUND_STEREO;
                        break;
                case V4L2_TUNER_MODE_LANG1:
diff --git a/drivers/media/video/tvaudio.h b/drivers/media/video/tvaudio.h
deleted file mode 100644 (file)
index af7e116..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * i2c bus addresses for the chips supported by tvaudio.c
- */
-
-#define I2C_TDA8425        0x82
-#define I2C_TDA9840        0x84 /* also used by TA8874Z */
-#define I2C_TDA985x_L      0xb4 /* also used by 9873 */
-#define I2C_TDA985x_H      0xb6
-#define I2C_TDA9874        0xb0 /* also used by 9875 */
-
-#define I2C_TEA6300        0x80 /* also used by 6320 */
-#define I2C_TEA6420       0x98
-
-#define I2C_PIC16C54       0x96 /* PV951 */
index 582551b0969b69f678d775b0ba84b72b800924d4..e0d2ff83fc917e8583a67bf5d8b45f783e027386 100644 (file)
@@ -248,32 +248,32 @@ audioIC[] =
        {AUDIO_CHIP_MSP34XX,  "MSP3410D"},
        {AUDIO_CHIP_MSP34XX,  "MSP3415"},
        {AUDIO_CHIP_MSP34XX,  "MSP3430"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP3438"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3438"},
        {AUDIO_CHIP_UNKNOWN,  "CS5331"},
        /* 10-14 */
        {AUDIO_CHIP_MSP34XX,  "MSP3435"},
        {AUDIO_CHIP_MSP34XX,  "MSP3440"},
        {AUDIO_CHIP_MSP34XX,  "MSP3445"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP3411"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP3416"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3411"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3416"},
        /* 15-19 */
        {AUDIO_CHIP_MSP34XX,  "MSP3425"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP3451"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP3418"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3451"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3418"},
        {AUDIO_CHIP_UNKNOWN,  "Type 0x12"},
        {AUDIO_CHIP_UNKNOWN,  "OKI7716"},
        /* 20-24 */
-       {AUDIO_CHIP_UNKNOWN,  "MSP4410"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4420"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4440"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4450"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4408"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4410"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4420"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4440"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4450"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4408"},
        /* 25-29 */
-       {AUDIO_CHIP_UNKNOWN,  "MSP4418"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4428"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4448"},
-       {AUDIO_CHIP_UNKNOWN,  "MSP4458"},
-       {AUDIO_CHIP_UNKNOWN,  "Type 0x1d"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4418"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4428"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4448"},
+       {AUDIO_CHIP_MSP34XX,  "MSP4458"},
+       {AUDIO_CHIP_MSP34XX,  "Type 0x1d"},
        /* 30-34 */
        {AUDIO_CHIP_INTERNAL, "CX880"},
        {AUDIO_CHIP_INTERNAL, "CX881"},
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
new file mode 100644 (file)
index 0000000..ed410a5
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_USB_IBMCAM)        += ibmcam.o usbvideo.o ultracam.o
+obj-$(CONFIG_USB_KONICAWC)      += konicawc.o usbvideo.o
+obj-$(CONFIG_USB_VICAM)         += vicam.o usbvideo.o
+
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
new file mode 100644 (file)
index 0000000..76f771b
--- /dev/null
@@ -0,0 +1,3932 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports Xirlink C-It Video Camera, IBM PC Camera,
+ * IBM NetCamera and Veo Stingray.
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * 5/24/00 Removed optional (and unnecessary) locking of the driver while
+ * the device remains plugged in. Corrected race conditions in ibmcam_open
+ * and ibmcam_probe() routines using this as a guideline:
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "usbvideo.h"
+
+#define IBMCAM_VENDOR_ID       0x0545
+#define IBMCAM_PRODUCT_ID      0x8080
+#define NETCAM_PRODUCT_ID      0x8002  /* IBM NetCamera, close to model 2 */
+#define VEO_800C_PRODUCT_ID    0x800C  /* Veo Stingray, repackaged Model 2 */
+#define VEO_800D_PRODUCT_ID    0x800D  /* Veo Stingray, repackaged Model 4 */
+
+#define MAX_IBMCAM             4       /* How many devices we allow to connect */
+#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
+
+/* Header signatures */
+
+/* Model 1 header: 00 FF 00 xx */
+#define HDRSIG_MODEL1_128x96   0x06    /* U Y V Y ... */
+#define HDRSIG_MODEL1_176x144  0x0e    /* U Y V Y ... */
+#define HDRSIG_MODEL1_352x288  0x00    /* V Y U Y ... */
+
+#define        IBMCAM_MODEL_1  1       /* XVP-501, 3 interfaces, rev. 0.02 */
+#define IBMCAM_MODEL_2 2       /* KSX-X9903, 2 interfaces, rev. 3.0a */
+#define IBMCAM_MODEL_3 3       /* KSX-X9902, 2 interfaces, rev. 3.01 */
+#define        IBMCAM_MODEL_4  4       /* IBM NetCamera, 0545/8002/3.0a */
+
+/* Video sizes supported */
+#define        VIDEOSIZE_128x96        VIDEOSIZE(128, 96)
+#define        VIDEOSIZE_176x144       VIDEOSIZE(176,144)
+#define        VIDEOSIZE_352x288       VIDEOSIZE(352,288)
+#define        VIDEOSIZE_320x240       VIDEOSIZE(320,240)
+#define        VIDEOSIZE_352x240       VIDEOSIZE(352,240)
+#define        VIDEOSIZE_640x480       VIDEOSIZE(640,480)
+#define        VIDEOSIZE_160x120       VIDEOSIZE(160,120)
+
+/* Video sizes supported */
+enum {
+       SIZE_128x96 = 0,
+       SIZE_160x120,
+       SIZE_176x144,
+       SIZE_320x240,
+       SIZE_352x240,
+       SIZE_352x288,
+       SIZE_640x480,
+       /* Add/remove/rearrange items before this line */
+       SIZE_LastItem
+};
+
+/*
+ * This structure lives in uvd->user field.
+ */
+typedef struct {
+       int initialized;        /* Had we already sent init sequence? */
+       int camera_model;       /* What type of IBM camera we got? */
+       int has_hdr;
+} ibmcam_t;
+#define        IBMCAM_T(uvd)   ((ibmcam_t *)((uvd)->user_data))
+
+static struct usbvideo *cams;
+
+static int debug;
+
+static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+static const int min_canvasWidth  = 8;
+static const int min_canvasHeight = 4;
+
+static int lighting = 1; /* Medium */
+
+#define SHARPNESS_MIN  0
+#define SHARPNESS_MAX  6
+static int sharpness = 4; /* Low noise, good details */
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  6
+static int framerate = -1;
+
+static int size = SIZE_352x288;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+static int hue_correction = 128;
+
+/* Settings for camera model 2 */
+static int init_model2_rg2 = -1;
+static int init_model2_sat = -1;
+static int init_model2_yb = -1;
+
+/* 01.01.08 - Added for RCA video in support -LO */
+/* Settings for camera model 3 */
+static int init_model3_input = 0;
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+module_param(flags, int, 0);
+MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
+module_param(framerate, int, 0);
+MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
+module_param(lighting, int, 0);
+MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
+module_param(sharpness, int, 0);
+MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480  (default=5)");
+module_param(init_brightness, int, 0);
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
+module_param(init_contrast, int, 0);
+MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
+module_param(init_color, int, 0);
+MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
+module_param(init_hue, int, 0);
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
+module_param(hue_correction, int, 0);
+MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
+
+module_param(init_model2_rg2, int, 0);
+MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
+module_param(init_model2_sat, int, 0);
+MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
+module_param(init_model2_yb, int, 0);
+MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
+
+/* 01.01.08 - Added for RCA video in support -LO */
+module_param(init_model3_input, int, 0);
+MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
+
+MODULE_AUTHOR ("Dmitri");
+MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
+MODULE_LICENSE("GPL");
+
+/* Still mysterious i2c commands */
+static const unsigned short unknown_88 = 0x0088;
+static const unsigned short unknown_89 = 0x0089;
+static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
+static const unsigned short contrast_14 = 0x0014;
+static const unsigned short light_27 = 0x0027;
+static const unsigned short sharp_13 = 0x0013;
+
+/* i2c commands for Model 2 cameras */
+static const unsigned short mod2_brightness = 0x001a;          /* $5b .. $ee; default=$5a */
+static const unsigned short mod2_set_framerate = 0x001c;       /* 0 (fast).. $1F (slow) */
+static const unsigned short mod2_color_balance_rg2 = 0x001e;   /* 0 (red) .. $7F (green) */
+static const unsigned short mod2_saturation = 0x0020;          /* 0 (b/w) - $7F (full color) */
+static const unsigned short mod2_color_balance_yb = 0x0022;    /* 0..$7F, $50 is about right */
+static const unsigned short mod2_hue = 0x0024;                 /* 0..$7F, $70 is about right */
+static const unsigned short mod2_sensitivity = 0x0028;         /* 0 (min) .. $1F (max) */
+
+struct struct_initData {
+       unsigned char req;
+       unsigned short value;
+       unsigned short index;
+};
+
+/*
+ * ibmcam_size_to_videosize()
+ *
+ * This procedure converts module option 'size' into the actual
+ * videosize_t that defines the image size in pixels. We need
+ * simplified 'size' because user wants a simple enumerated list
+ * of choices, not an infinite set of possibilities.
+ */
+static videosize_t ibmcam_size_to_videosize(int size)
+{
+       videosize_t vs = VIDEOSIZE_352x288;
+       RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
+       switch (size) {
+       case SIZE_128x96:
+               vs = VIDEOSIZE_128x96;
+               break;
+       case SIZE_160x120:
+               vs = VIDEOSIZE_160x120;
+               break;
+       case SIZE_176x144:
+               vs = VIDEOSIZE_176x144;
+               break;
+       case SIZE_320x240:
+               vs = VIDEOSIZE_320x240;
+               break;
+       case SIZE_352x240:
+               vs = VIDEOSIZE_352x240;
+               break;
+       case SIZE_352x288:
+               vs = VIDEOSIZE_352x288;
+               break;
+       case SIZE_640x480:
+               vs = VIDEOSIZE_640x480;
+               break;
+       default:
+               err("size=%d. is not valid", size);
+               break;
+       }
+       return vs;
+}
+
+/*
+ * ibmcam_find_header()
+ *
+ * Locate one of supported header markers in the queue.
+ * Once found, remove all preceding bytes AND the marker (4 bytes)
+ * from the data pump queue. Whatever follows must be video lines.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
+{
+       struct usbvideo_frame *frame;
+       ibmcam_t *icam;
+
+       if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
+               err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
+               return scan_EndParse;
+       }
+       icam = IBMCAM_T(uvd);
+       assert(icam != NULL);
+       frame = &uvd->frame[uvd->curframe];
+       icam->has_hdr = 0;
+       switch (icam->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int marker_len = 4;
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
+                       {
+#if 0                          /* This code helps to detect new frame markers */
+                               info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
+#endif
+                               frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               if ((frame->header == HDRSIG_MODEL1_128x96) ||
+                                   (frame->header == HDRSIG_MODEL1_176x144) ||
+                                   (frame->header == HDRSIG_MODEL1_352x288))
+                               {
+#if 0
+                                       info("Header found.");
+#endif
+                                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                                       icam->has_hdr = 1;
+                                       break;
+                               }
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+case IBMCAM_MODEL_4:
+       {
+               int marker_len = 0;
+               switch (uvd->videosize) {
+               case VIDEOSIZE_176x144:
+                       marker_len = 10;
+                       break;
+               default:
+                       marker_len = 2;
+                       break;
+               }
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
+                       {
+#if 0
+                               info("Header found.");
+#endif
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                               icam->has_hdr = 1;
+                               frame->header = HDRSIG_MODEL1_176x144;
+                               break;
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {       /*
+                * Headers: (one precedes every frame). nc=no compression,
+                * bq=best quality bf=best frame rate.
+                *
+                * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
+                * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
+                * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
+                *
+                * Bytes '00 FF' seem to indicate header. Other two bytes
+                * encode the frame type. This is a set of bit fields that
+                * encode image size, compression type etc. These fields
+                * do NOT contain frame number because all frames carry
+                * the same header.
+                */
+               const int marker_len = 4;
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
+                       {
+                               /*
+                                * Combine 2 bytes of frame type into one
+                                * easy to use value
+                                */
+                               unsigned long byte3, byte4;
+
+                               byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
+                               byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               frame->header = (byte3 << 8) | byte4;
+#if 0
+                               info("Header found.");
+#endif
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                               icam->has_hdr = 1;
+                               break;
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       if (!icam->has_hdr) {
+               if (uvd->debug > 2)
+                       info("Skipping frame, no header");
+               return scan_EndParse;
+       }
+
+       /* Header found */
+       icam->has_hdr = 1;
+       uvd->stats.header_count++;
+       frame->scanstate = ScanState_Lines;
+       frame->curline = 0;
+
+       if (flags & FLAGS_FORCE_TESTPATTERN) {
+               usbvideo_TestPattern(uvd, 1, 1);
+               return scan_NextFrame;
+       }
+       return scan_Continue;
+}
+
+/*
+ * ibmcam_parse_lines()
+ *
+ * Parse one line (interlaced) from the buffer, put
+ * decoded RGB value into the current frame buffer
+ * and add the written number of bytes (RGB) to
+ * the *pcopylen.
+ *
+ * History:
+ * 21-Jan-2000 Created.
+ * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
+ */
+static enum ParseState ibmcam_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       unsigned char *f;
+       ibmcam_t *icam;
+       unsigned int len, scanLength, scanHeight, order_uv, order_yc;
+       int v4l_linesize; /* V4L line offset */
+       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
+       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
+       const int ccm = 128; /* Color correction median - see below */
+       int y, u, v, i, frame_done=0, color_corr;
+       static unsigned char lineBuffer[640*3];
+       unsigned const char *chromaLine, *lumaLine;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+       icam = IBMCAM_T(uvd);
+       assert(icam != NULL);
+       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
+
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
+               /* Model 4 frame markers do not carry image size identification */
+               switch (uvd->videosize) {
+               case VIDEOSIZE_128x96:
+               case VIDEOSIZE_160x120:
+               case VIDEOSIZE_176x144:
+                       scanLength = VIDEOSIZE_X(uvd->videosize);
+                       scanHeight = VIDEOSIZE_Y(uvd->videosize);
+                       break;
+               default:
+                       err("ibmcam_parse_lines: Wrong mode.");
+                       return scan_Out;
+               }
+               order_yc = 1;   /* order_yc: true=Yc false=cY ('c'=either U or V) */
+               order_uv = 1;   /* Always true in this algorithm */
+       } else {
+               switch (frame->header) {
+               case HDRSIG_MODEL1_128x96:
+                       scanLength = 128;
+                       scanHeight = 96;
+                       order_uv = 1;   /* U Y V Y ... */
+                       break;
+               case HDRSIG_MODEL1_176x144:
+                       scanLength = 176;
+                       scanHeight = 144;
+                       order_uv = 1;   /* U Y V Y ... */
+                       break;
+               case HDRSIG_MODEL1_352x288:
+                       scanLength = 352;
+                       scanHeight = 288;
+                       order_uv = 0;   /* Y V Y V ... */
+                       break;
+               default:
+                       err("Unknown header signature 00 FF 00 %02lX", frame->header);
+                       return scan_NextFrame;
+               }
+               /* order_yc: true=Yc false=cY ('c'=either U or V) */
+               order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
+       }
+
+       len = scanLength * 3;
+       assert(len <= sizeof(lineBuffer));
+
+       /*
+        * Lines are organized this way:
+        *
+        * I420:
+        * ~~~~
+        * <scanLength->
+        * ___________________________________
+        * |-----Y-----|---UVUVUV...UVUV-----| \
+        * |-----------+---------------------|  \
+        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. lines (interlaced)
+        * |...    ... |        ...          |  /
+        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. lines (interlaced)
+        * |___________|_____________________| /
+        *  \           \
+        *   lumaLine    chromaLine
+        */
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Mind that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
+               return scan_NextFrame;
+
+       /*
+        * Now we are sure that entire line (representing all 'scanLength'
+        * pixels from the camera) is available in the buffer. We
+        * start copying the line left-aligned to the V4L buffer.
+        * If the camera line is shorter then we should pad the V4L
+        * buffer with something (black) to complete the line.
+        */
+       assert(frame->data != NULL);
+       f = frame->data + (v4l_linesize * frame->curline);
+
+       /*
+        * To obtain chrominance data from the 'chromaLine' use this:
+        *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
+        *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
+        *
+        * Indices must be calculated this way:
+        * v_index = (i >> 1) << 2;
+        * u_index = (i >> 1) << 2 + 2;
+        *
+        * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
+        */
+       lumaLine = lineBuffer;
+       chromaLine = lineBuffer + scanLength;
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
+       {
+               unsigned char rv, gv, bv;       /* RGB components */
+
+               /* Check for various visual debugging hints (colorized pixels) */
+               if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
+                       /*
+                        * This is bad and should not happen. This means that
+                        * we somehow overshoot the line and encountered new
+                        * frame! Obviously our camera/V4L frame size is out
+                        * of whack. This cyan dot will help you to figure
+                        * out where exactly the new frame arrived.
+                        */
+                       if (icam->has_hdr == 1) {
+                               bv = 0; /* Yellow marker */
+                               gv = 0xFF;
+                               rv = 0xFF;
+                       } else {
+                               bv = 0xFF; /* Cyan marker */
+                               gv = 0xFF;
+                               rv = 0;
+                       }
+                       icam->has_hdr = 0;
+                       goto make_pixel;
+               }
+
+               /*
+                * Check if we are still in range. We may be out of range if our
+                * V4L canvas is wider or taller than the camera "native" image.
+                * Then we quickly fill the remainder of the line with zeros to
+                * make black color and quit the horizontal scanning loop.
+                */
+               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
+                       const int j = i * V4L_BYTES_PER_PIXEL;
+#if USES_IBMCAM_PUTPIXEL
+                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
+                       f = frame->data + (v4l_linesize * frame->curline) + j;
+#endif
+                       memset(f, 0, v4l_linesize - j);
+                       break;
+               }
+
+               y = lumaLine[i];
+               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+                       rv = gv = bv = y;
+               else {
+                       int off_0, off_2;
+
+                       off_0 = (i >> 1) << 2;
+                       off_2 = off_0 + 2;
+
+                       if (order_yc) {
+                               off_0++;
+                               off_2++;
+                       }
+                       if (!order_uv) {
+                               off_0 += 2;
+                               off_2 -= 2;
+                       }
+                       u = chromaLine[off_0] + hue_corr;
+                       v = chromaLine[off_2] + hue2_corr;
+
+                       /* Apply color correction */
+                       if (color_corr != 0) {
+                               /* Magnify up to 2 times, reduce down to zero saturation */
+                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
+                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
+                       }
+                       YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+               }
+
+       make_pixel:
+               /*
+                * The purpose of creating the pixel here, in one,
+                * dedicated place is that we may need to make the
+                * pixel wider and taller than it actually is. This
+                * may be used if camera generates small frames for
+                * sake of frame rate (or any other reason.)
+                *
+                * The output data consists of B, G, R bytes
+                * (in this order).
+                */
+#if USES_IBMCAM_PUTPIXEL
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+#else
+               *f++ = bv;
+               *f++ = gv;
+               *f++ = rv;
+#endif
+               /*
+                * Typically we do not decide within a legitimate frame
+                * that we want to end the frame. However debugging code
+                * may detect marker of new frame within the data. Then
+                * this condition activates. The 'data' pointer is already
+                * pointing at the new marker, so we'd better leave it as is.
+                */
+               if (frame_done)
+                       break;  /* End scanning of lines */
+       }
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       if (pcopylen != NULL)
+               *pcopylen += 2 * v4l_linesize;
+       frame->deinterlace = Deinterlace_FillOddLines;
+
+       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
+               return scan_NextFrame;
+       else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_model2_320x240_parse_lines()
+ *
+ * This procedure deals with a weird RGB format that is produced by IBM
+ * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
+ * depending on horizontal size of the picture:
+ *
+ * <--- 160 or 176 pairs of RA,RB bytes ----->
+ * *-----------------------------------------* \
+ * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \   This is pair of horizontal lines,
+ * |-----+-----+-----+-----+ ... +-----+-----|   *- or one interlaced line, total
+ * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   120 or 144 such pairs which yield
+ * |=====+=====+=====+=====+ ... +=====+=====| /    240 or 288 lines after deinterlacing.
+ *
+ * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
+ * defines ONE pixel. Therefore this format yields 176x144 "decoded"
+ * resolution at best. I do not know why camera sends such format - the
+ * previous model (1) just used interlaced I420 and everyone was happy.
+ *
+ * I do not know what is the difference between RAi and RBi bytes. Both
+ * seemingly represent R component, but slightly vary in value (so that
+ * the picture looks a bit colored if one or another is used). I use
+ * them both as R component in attempt to at least partially recover the
+ * lost resolution.
+ */
+static enum ParseState ibmcam_model2_320x240_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       unsigned char *f, *la, *lb;
+       unsigned int len;
+       int v4l_linesize; /* V4L line offset */
+       int i, j, frame_done=0, color_corr;
+       int scanLength, scanHeight;
+       static unsigned char lineBuffer[352*2];
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_320x240:
+       case VIDEOSIZE_352x240:
+       case VIDEOSIZE_352x288:
+               scanLength = VIDEOSIZE_X(uvd->videosize);
+               scanHeight = VIDEOSIZE_Y(uvd->videosize);
+               break;
+       default:
+               err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
+               return scan_Out;
+       }
+
+       color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       len = scanLength * 2; /* See explanation above */
+       assert(len <= sizeof(lineBuffer));
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Mind that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
+               return scan_NextFrame;
+
+       la = lineBuffer;
+       lb = lineBuffer + scanLength;
+
+       /*
+        * Now we are sure that entire line (representing all
+        *         VIDEOSIZE_X(frame->request)
+        * pixels from the camera) is available in the scratch buffer. We
+        * start copying the line left-aligned to the V4L buffer (which
+        * might be larger - not smaller, hopefully). If the camera
+        * line is shorter then we should pad the V4L buffer with something
+        * (black in this case) to complete the line.
+        */
+       f = frame->data + (v4l_linesize * frame->curline);
+
+       /* Fill the 2-line strip */
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int y, rv, gv, bv;      /* RGB components */
+
+               j = i & (~1);
+
+               /* Check for various visual debugging hints (colorized pixels) */
+               if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
+                       if (IBMCAM_T(uvd)->has_hdr == 1) {
+                               bv = 0; /* Yellow marker */
+                               gv = 0xFF;
+                               rv = 0xFF;
+                       } else {
+                               bv = 0xFF; /* Cyan marker */
+                               gv = 0xFF;
+                               rv = 0;
+                       }
+                       IBMCAM_T(uvd)->has_hdr = 0;
+                       goto make_pixel;
+               }
+
+               /*
+                * Check if we are still in range. We may be out of range if our
+                * V4L canvas is wider or taller than the camera "native" image.
+                * Then we quickly fill the remainder of the line with zeros to
+                * make black color and quit the horizontal scanning loop.
+                */
+               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
+                       const int j = i * V4L_BYTES_PER_PIXEL;
+#if USES_IBMCAM_PUTPIXEL
+                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
+                       f = frame->data + (v4l_linesize * frame->curline) + j;
+#endif
+                       memset(f, 0, v4l_linesize - j);
+                       break;
+               }
+
+               /*
+                * Here I use RA and RB components, one per physical pixel.
+                * This causes fine vertical grid on the picture but may improve
+                * horizontal resolution. If you prefer replicating, use this:
+                *   rv = la[j + 0];   ... or ... rv = la[j + 1];
+                * then the pixel will be replicated.
+                */
+               rv = la[i];
+               gv = lb[j + 1];
+               bv = lb[j + 0];
+
+               y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
+
+               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+                       rv = gv = bv = y;
+               else if (color_corr != 128) {
+
+                       /* Calculate difference between color and brightness */
+                       rv -= y;
+                       gv -= y;
+                       bv -= y;
+
+                       /* Scale differences */
+                       rv = (rv * color_corr) / 128;
+                       gv = (gv * color_corr) / 128;
+                       bv = (bv * color_corr) / 128;
+
+                       /* Reapply brightness */
+                       rv += y;
+                       gv += y;
+                       bv += y;
+
+                       /* Watch for overflows */
+                       RESTRICT_TO_RANGE(rv, 0, 255);
+                       RESTRICT_TO_RANGE(gv, 0, 255);
+                       RESTRICT_TO_RANGE(bv, 0, 255);
+               }
+
+       make_pixel:
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+       }
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       *pcopylen += v4l_linesize * 2;
+       frame->deinterlace = Deinterlace_FillOddLines;
+
+       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
+               return scan_NextFrame;
+       else
+               return scan_Continue;
+}
+
+static enum ParseState ibmcam_model3_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       unsigned char *data;
+       const unsigned char *color;
+       unsigned int len;
+       int v4l_linesize; /* V4L line offset */
+       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
+       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
+       const int ccm = 128; /* Color correction median - see below */
+       int i, u, v, rw, data_w=0, data_h=0, color_corr;
+       static unsigned char lineBuffer[640*3];
+
+       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
+
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       /* The header tells us what sort of data is in this frame */
+       switch (frame->header) {
+               /*
+                * Uncompressed modes (that are easy to decode).
+                */
+       case 0x0308:
+               data_w = 640;
+               data_h = 480;
+               break;
+       case 0x0208:
+               data_w = 320;
+               data_h = 240;
+               break;
+       case 0x020A:
+               data_w = 160;
+               data_h = 120;
+               break;
+               /*
+                * Compressed modes (ViCE - that I don't know how to decode).
+                */
+       case 0x0328:    /* 640x480, best quality compression */
+       case 0x0368:    /* 640x480, best frame rate compression */
+       case 0x0228:    /* 320x240, best quality compression */
+       case 0x0268:    /* 320x240, best frame rate compression */
+       case 0x02CA:    /* 160x120, best quality compression */
+       case 0x02EA:    /* 160x120, best frame rate compression */
+               /* Do nothing with this - not supported */
+               err("Unsupported mode $%04lx", frame->header);
+               return scan_NextFrame;
+       default:
+               /* Catch unknown headers, may help in learning new headers */
+               err("Strange frame->header=$%08lx", frame->header);
+               return scan_NextFrame;
+       }
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Note that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= data_h) {
+               if (uvd->debug >= 3)
+                       info("Reached line %d. (frame is done)", frame->curline);
+               return scan_NextFrame;
+       }
+
+       /* Make sure there's enough data for the entire line */
+       len = 3 * data_w; /* <y-data> <uv-data> */
+       assert(len <= sizeof(lineBuffer));
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       data = lineBuffer;
+       color = data + data_w;          /* Point to where color planes begin */
+
+       /* Bottom-to-top scanning */
+       rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
+       RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
+
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int y, rv, gv, bv;      /* RGB components */
+
+               if (i < data_w) {
+                       y = data[i];    /* Luminosity is the first line */
+
+                       /* Apply static color correction */
+                       u = color[i*2] + hue_corr;
+                       v = color[i*2 + 1] + hue2_corr;
+
+                       /* Apply color correction */
+                       if (color_corr != 0) {
+                               /* Magnify up to 2 times, reduce down to zero saturation */
+                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
+                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
+                       }
+               } else
+                       y = 0, u = v = 128;
+
+               YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+               RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
+       }
+       frame->deinterlace = Deinterlace_FillEvenLines;
+
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       *pcopylen += 2 * v4l_linesize;
+
+       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
+               if (uvd->debug >= 3) {
+                       info("All requested lines (%ld.) done.",
+                            VIDEOSIZE_Y(frame->request));
+               }
+               return scan_NextFrame;
+       } else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_model4_128x96_parse_lines()
+ *
+ * This decoder is for one strange data format that is produced by Model 4
+ * camera only in 128x96 mode. This is RGB format and here is its description.
+ * First of all, this is non-interlaced stream, meaning that all scan lines
+ * are present in the datastream. There are 96 consecutive blocks of data
+ * that describe all 96 lines of the image. Each block is 5*128 bytes long
+ * and carries R, G, B components. The format of the block is shown in the
+ * code below. First 128*2 bytes are interleaved R and G components. Then
+ * we have a gap (junk data) 64 bytes long. Then follow B and something
+ * else, also interleaved (this makes another 128*2 bytes). After that
+ * probably another 64 bytes of junk follow.
+ *
+ * History:
+ * 10-Feb-2001 Created.
+ */
+static enum ParseState ibmcam_model4_128x96_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       const unsigned char *data_rv, *data_gv, *data_bv;
+       unsigned int len;
+       int i, v4l_linesize; /* V4L line offset */
+       const int data_w=128, data_h=96;
+       static unsigned char lineBuffer[128*5];
+
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Note that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= data_h) {
+               if (uvd->debug >= 3)
+                       info("Reached line %d. (frame is done)", frame->curline);
+               return scan_NextFrame;
+       }
+
+       /*
+        * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
+        * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
+        */
+
+       /* Make sure there's enough data for the entire line */
+       len = 5 * data_w;
+       assert(len <= sizeof(lineBuffer));
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       data_rv = lineBuffer;
+       data_gv = lineBuffer + 1;
+       data_bv = lineBuffer + data_w*2 + data_w/2;
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int rv, gv, bv; /* RGB components */
+               if (i < data_w) {
+                       const int j = i * 2;
+                       gv = data_rv[j];
+                       rv = data_gv[j];
+                       bv = data_bv[j];
+                       if (flags & FLAGS_MONOCHROME) {
+                               unsigned long y;
+                               y = rv + gv + bv;
+                               y /= 3;
+                               if (y > 0xFF)
+                                       y = 0xFF;
+                               rv = gv = bv = (unsigned char) y;
+                       }
+               } else {
+                       rv = gv = bv = 0;
+               }
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+       }
+       frame->deinterlace = Deinterlace_None;
+       frame->curline++;
+       *pcopylen += v4l_linesize;
+
+       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
+               if (uvd->debug >= 3) {
+                       info("All requested lines (%ld.) done.",
+                            VIDEOSIZE_Y(frame->request));
+               }
+               return scan_NextFrame;
+       } else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ibmcam_find_header() or ibmcam_parse_lines() to do most
+ * of work.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static void ibmcam_ProcessIsocData(struct uvd *uvd,
+                                  struct usbvideo_frame *frame)
+{
+       enum ParseState newstate;
+       long copylen = 0;
+       int mod = IBMCAM_T(uvd)->camera_model;
+
+       while (1) {
+               newstate = scan_Out;
+               if (RingQueue_GetLength(&uvd->dp) > 0) {
+                       if (frame->scanstate == ScanState_Scanning) {
+                               newstate = ibmcam_find_header(uvd);
+                       } else if (frame->scanstate == ScanState_Lines) {
+                               if ((mod == IBMCAM_MODEL_2) &&
+                                   ((uvd->videosize == VIDEOSIZE_352x288) ||
+                                    (uvd->videosize == VIDEOSIZE_320x240) ||
+                                    (uvd->videosize == VIDEOSIZE_352x240)))
+                               {
+                                       newstate = ibmcam_model2_320x240_parse_lines(
+                                               uvd, frame, &copylen);
+                               } else if (mod == IBMCAM_MODEL_4) {
+                                       /*
+                                        * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
+                                        * for 320x240 and above; 160x120 and 176x144 uses Model 1
+                                        * decoder (YUV), and 128x96 mode uses ???
+                                        */
+                                       if ((uvd->videosize == VIDEOSIZE_352x288) ||
+                                           (uvd->videosize == VIDEOSIZE_320x240) ||
+                                           (uvd->videosize == VIDEOSIZE_352x240))
+                                       {
+                                               newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
+                                       } else if (uvd->videosize == VIDEOSIZE_128x96) {
+                                               newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
+                                       } else {
+                                               newstate = ibmcam_parse_lines(uvd, frame, &copylen);
+                                       }
+                               } else if (mod == IBMCAM_MODEL_3) {
+                                       newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
+                               } else {
+                                       newstate = ibmcam_parse_lines(uvd, frame, &copylen);
+                               }
+                       }
+               }
+               if (newstate == scan_Continue)
+                       continue;
+               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
+                       break;
+               else
+                       return; /* scan_EndParse */
+       }
+
+       if (newstate == scan_NextFrame) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+               if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
+                       /* Need software contrast adjustment for those cameras */
+                       frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
+               }
+       }
+
+       /* Update the frame's uncompressed length. */
+       frame->seqRead_Length += copylen;
+
+#if 0
+       {
+               static unsigned char j=0;
+               memset(frame->data, j++, uvd->max_frame_size);
+               frame->frameState = FrameState_Ready;
+       }
+#endif
+}
+
+/*
+ * ibmcam_veio()
+ *
+ * History:
+ * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
+ */
+static int ibmcam_veio(
+       struct uvd *uvd,
+       unsigned char req,
+       unsigned short value,
+       unsigned short index)
+{
+       static const char proc[] = "ibmcam_veio";
+       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+       int i;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return 0;
+
+       if (req == 1) {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_rcvctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value,
+                       index,
+                       cp,
+                       sizeof(cp),
+                       1000);
+#if 0
+               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x)",
+                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                      req, value, index);
+#endif
+       } else {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_sndctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       1000);
+       }
+       if (i < 0) {
+               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
+                   proc, i);
+               uvd->last_error = i;
+       }
+       return i;
+}
+
+/*
+ * ibmcam_calculate_fps()
+ *
+ * This procedure roughly calculates the real frame rate based
+ * on FPS code (framerate=NNN option). Actual FPS differs
+ * slightly depending on lighting conditions, so that actual frame
+ * rate is determined by the camera. Since I don't know how to ask
+ * the camera what FPS is now I have to use the FPS code instead.
+ *
+ * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
+ * Corresponding real FPS should be in range [3..30] frames per second.
+ * The conversion formula is obvious:
+ *
+ * real_fps = 3 + (fps_code * 4.5)
+ *
+ * History:
+ * 1/18/00  Created.
+ */
+static int ibmcam_calculate_fps(struct uvd *uvd)
+{
+       return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * ibmcam_send_FF_04_02()
+ *
+ * This procedure sends magic 3-command prefix to the camera.
+ * The purpose of this prefix is not known.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void ibmcam_send_FF_04_02(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
+       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+}
+
+static void ibmcam_send_00_04_06(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0006, 0x0124);
+}
+
+static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+}
+
+static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_send_x_00(uvd, x);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+}
+
+static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+}
+
+static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+}
+
+static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+}
+
+static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0008, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+}
+
+static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
+{
+       ibmcam_send_x_01_00_05(uvd, unknown_88);
+       ibmcam_send_x_00_05(uvd, fkey);
+       ibmcam_send_x_00_05_02_08_01(uvd, val);
+       ibmcam_send_x_00_05(uvd, unknown_88);
+       ibmcam_send_x_00_05_02_01(uvd, fkey);
+       ibmcam_send_x_00_05(uvd, unknown_89);
+       ibmcam_send_x_00(uvd, fkey);
+       ibmcam_send_00_04_06(uvd);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0126);
+       ibmcam_send_FF_04_02(uvd);
+}
+
+static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
+{
+       ibmcam_send_x_01_00_05  (uvd, unknown_88);
+       ibmcam_send_x_00_05     (uvd, fkey);
+       ibmcam_send_x_00_05_02  (uvd, val);
+}
+
+static void ibmcam_model2_Packet2(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
+       ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
+}
+
+static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
+{
+       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
+       ibmcam_veio(uvd, 0, v1,     0x012f);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
+       ibmcam_veio(uvd, 0, 0xc719, 0x0124);
+       ibmcam_veio(uvd, 0, v2,     0x0127);
+
+       ibmcam_model2_Packet2(uvd);
+}
+
+/*
+ * ibmcam_model3_Packet1()
+ *
+ * 00_0078_012d
+ * 00_0097_012f
+ * 00_d141_0124
+ * 00_0096_0127
+ * 00_fea8_0124
+*/
+static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
+{
+       ibmcam_veio(uvd, 0, 0x0078, 0x012d);
+       ibmcam_veio(uvd, 0, v1,     0x012f);
+       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+       ibmcam_veio(uvd, 0, v2,     0x0127);
+       ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+}
+
+static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
+{
+       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+       ibmcam_veio(uvd, 0, 0x0026, 0x012f);
+       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+       ibmcam_veio(uvd, 0, i,      0x0127);
+       ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+       ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0038, 0x012d);
+       ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+       ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+       ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+}
+
+/*
+ * ibmcam_adjust_contrast()
+ *
+ * The contrast value changes from 0 (high contrast) to 15 (low contrast).
+ * This is in reverse to usual order of things (such as TV controls), so
+ * we reverse it again here.
+ *
+ * TODO: we probably don't need to send the setup 5 times...
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void ibmcam_adjust_contrast(struct uvd *uvd)
+{
+       unsigned char a_contrast = uvd->vpic.contrast >> 12;
+       unsigned char new_contrast;
+
+       if (a_contrast >= 16)
+               a_contrast = 15;
+       new_contrast = 15 - a_contrast;
+       if (new_contrast == uvd->vpic_old.contrast)
+               return;
+       uvd->vpic_old.contrast = new_contrast;
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int ntries = 5;
+               int i;
+               for (i=0; i < ntries; i++) {
+                       ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
+                       ibmcam_send_FF_04_02(uvd);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       case IBMCAM_MODEL_4:
+               /* Models 2, 4 do not have this control; implemented in software. */
+               break;
+       case IBMCAM_MODEL_3:
+       {       /* Preset hardware values */
+               static const struct {
+                       unsigned short cv1;
+                       unsigned short cv2;
+                       unsigned short cv3;
+               } cv[7] = {
+                       { 0x05, 0x05, 0x0f },   /* Minimum */
+                       { 0x04, 0x04, 0x16 },
+                       { 0x02, 0x03, 0x16 },
+                       { 0x02, 0x08, 0x16 },
+                       { 0x01, 0x0c, 0x16 },
+                       { 0x01, 0x0e, 0x16 },
+                       { 0x01, 0x10, 0x16 }    /* Maximum */
+               };
+               int i = a_contrast / 2;
+               RESTRICT_TO_RANGE(i, 0, 6);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
+               ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
+               ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_change_lighting_conditions()
+ *
+ * Camera model 1:
+ * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
+ *
+ * Camera model 2:
+ * We have 16 levels of lighting, 0 for bright light and up to 15 for
+ * low light. But values above 5 or so are useless because camera is
+ * not really capable to produce anything worth viewing at such light.
+ * This setting may be altered only in certain camera state.
+ *
+ * Low lighting forces slower FPS. Lighting is set as a module parameter.
+ *
+ * History:
+ * 1/5/00   Created.
+ * 2/20/00  Added support for Model 2 cameras.
+ */
+static void ibmcam_change_lighting_conditions(struct uvd *uvd)
+{
+       static const char proc[] = "ibmcam_change_lighting_conditions";
+
+       if (debug > 0)
+               info("%s: Set lighting to %hu.", proc, lighting);
+
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int ntries = 5;
+               int i;
+               for (i=0; i < ntries; i++)
+                       ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
+               break;
+       }
+       case IBMCAM_MODEL_2:
+#if 0
+               /*
+                * This command apparently requires camera to be stopped. My
+                * experiments showed that it -is- possible to alter the lighting
+                * conditions setting "on the fly", but why bother? This setting does
+                * not work reliably in all cases, so I decided simply to leave the
+                * setting where Xirlink put it - in the camera setup phase. This code
+                * is commented out because it does not work at -any- moment, so its
+                * presence makes no sense. You may use it for experiments.
+                */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop camera */
+               ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Start camera */
+#endif
+               break;
+       case IBMCAM_MODEL_3:
+       case IBMCAM_MODEL_4:
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_set_sharpness()
+ *
+ * Cameras model 1 have internal smoothing feature. It is controlled by value in
+ * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
+ * Recommended value is 4. Cameras model 2 do not have this feature at all.
+ */
+static void ibmcam_set_sharpness(struct uvd *uvd)
+{
+       static const char proc[] = "ibmcam_set_sharpness";
+
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
+               unsigned short i, sv;
+
+               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+               if (debug > 0)
+                       info("%s: Set sharpness to %hu.", proc, sharpness);
+
+               sv = sa[sharpness - SHARPNESS_MIN];
+               for (i=0; i < 2; i++) {
+                       ibmcam_send_x_01_00_05  (uvd, unknown_88);
+                       ibmcam_send_x_00_05             (uvd, sharp_13);
+                       ibmcam_send_x_00_05_02  (uvd, sv);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       case IBMCAM_MODEL_4:
+               /* Models 2, 4 do not have this control */
+               break;
+       case IBMCAM_MODEL_3:
+       {       /*
+                * "Use a table of magic numbers.
+                *  This setting doesn't really change much.
+                *  But that's how Windows does it."
+                */
+               static const struct {
+                       unsigned short sv1;
+                       unsigned short sv2;
+                       unsigned short sv3;
+                       unsigned short sv4;
+               } sv[7] = {
+                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
+                       { 0x01, 0x04, 0x05, 0x14 },
+                       { 0x02, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x05, 0x05, 0x14 },
+                       { 0x03, 0x06, 0x05, 0x14 },
+                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
+               };
+               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+               RESTRICT_TO_RANGE(sharpness, 0, 6);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
+               ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
+               ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
+               ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_set_brightness()
+ *
+ * This procedure changes brightness of the picture.
+ */
+static void ibmcam_set_brightness(struct uvd *uvd)
+{
+       static const char proc[] = "ibmcam_set_brightness";
+       static const unsigned short n = 1;
+
+       if (debug > 0)
+               info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
+
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               unsigned short i, j, bv[3];
+               bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
+               if (bv[0] == (uvd->vpic_old.brightness >> 10))
+                       return;
+               uvd->vpic_old.brightness = bv[0];
+               for (j=0; j < 3; j++)
+                       for (i=0; i < n; i++)
+                               ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       {
+               unsigned short i, j;
+               i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
+               j = 0x60 + i * ((0xee - 0x60) / 16);    /* 0x60 .. 0xee or so */
+               if (uvd->vpic_old.brightness == j)
+                       break;
+               uvd->vpic_old.brightness = j;
+               ibmcam_model2_Packet1(uvd, mod2_brightness, j);
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {
+               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
+               unsigned short i =
+                       0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
+               RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
+               if (uvd->vpic_old.brightness == i)
+                       break;
+               uvd->vpic_old.brightness = i;
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0036, i);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+               break;
+       }
+       case IBMCAM_MODEL_4:
+       {
+               /* Model 4: Brightness range 'i' in [0x04..0xb4] */
+               unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
+               RESTRICT_TO_RANGE(i, 0x04, 0xb4);
+               if (uvd->vpic_old.brightness == i)
+                       break;
+               uvd->vpic_old.brightness = i;
+               ibmcam_model4_BrightnessPacket(uvd, i);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static void ibmcam_set_hue(struct uvd *uvd)
+{
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_2:
+       {
+               unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
+               if (uvd->vpic_old.hue == hue)
+                       return;
+               uvd->vpic_old.hue = hue;
+               ibmcam_model2_Packet1(uvd, mod2_hue, hue);
+               /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {
+#if 0 /* This seems not to work. No problem, will fix programmatically */
+               unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
+               RESTRICT_TO_RANGE(hue, 0x05, 0x37);
+               if (uvd->vpic_old.hue == hue)
+                       return;
+               uvd->vpic_old.hue = hue;
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x007e, hue);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+#endif
+               break;
+       }
+       case IBMCAM_MODEL_4:
+       {
+               unsigned short r_gain, g_gain, b_gain, hue;
+
+               /*
+                * I am not sure r/g/b_gain variables exactly control gain
+                * of those channels. Most likely they subtly change some
+                * very internal image processing settings in the camera.
+                * In any case, here is what they do, and feel free to tweak:
+                *
+                * r_gain: seriously affects red gain
+                * g_gain: seriously affects green gain
+                * b_gain: seriously affects blue gain
+                * hue: changes average color from violet (0) to red (0xFF)
+                *
+                * These settings are preset for a decent white balance in
+                * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
+                * and therefore may need different values here.
+                */
+               hue = 20 + (uvd->vpic.hue >> 9);
+               switch (uvd->videosize) {
+               case VIDEOSIZE_128x96:
+                       r_gain = 90;
+                       g_gain = 166;
+                       b_gain = 175;
+                       break;
+               case VIDEOSIZE_160x120:
+                       r_gain = 70;
+                       g_gain = 166;
+                       b_gain = 185;
+                       break;
+               case VIDEOSIZE_176x144:
+                       r_gain = 160;
+                       g_gain = 175;
+                       b_gain = 185;
+                       break;
+               default:
+                       r_gain = 120;
+                       g_gain = 166;
+                       b_gain = 175;
+                       break;
+               }
+               RESTRICT_TO_RANGE(hue, 1, 0x7f);
+
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, g_gain, 0x0127);    /* Green gain */
+               ibmcam_veio(uvd, 0, r_gain, 0x012e);    /* Red gain */
+               ibmcam_veio(uvd, 0, b_gain, 0x0130);    /* Blue gain */
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, hue,    0x012d);    /* Hue */
+               ibmcam_veio(uvd, 0, 0xf545, 0x0124);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_adjust_picture()
+ *
+ * This procedure gets called from V4L interface to update picture settings.
+ * Here we change brightness and contrast.
+ */
+static void ibmcam_adjust_picture(struct uvd *uvd)
+{
+       ibmcam_adjust_contrast(uvd);
+       ibmcam_set_brightness(uvd);
+       ibmcam_set_hue(uvd);
+}
+
+static int ibmcam_model1_setup(struct uvd *uvd)
+{
+       const int ntries = 5;
+       int i;
+
+       ibmcam_veio(uvd, 1, 0x00, 0x0128);
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 0, 0x01, 0x0108);
+
+       ibmcam_veio(uvd, 0, 0x03, 0x0112);
+       ibmcam_veio(uvd, 1, 0x00, 0x0115);
+       ibmcam_veio(uvd, 0, 0x06, 0x0115);
+       ibmcam_veio(uvd, 1, 0x00, 0x0116);
+       ibmcam_veio(uvd, 0, 0x44, 0x0116);
+       ibmcam_veio(uvd, 1, 0x00, 0x0116);
+       ibmcam_veio(uvd, 0, 0x40, 0x0116);
+       ibmcam_veio(uvd, 1, 0x00, 0x0115);
+       ibmcam_veio(uvd, 0, 0x0e, 0x0115);
+       ibmcam_veio(uvd, 0, 0x19, 0x012c);
+
+       ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x09);
+       ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
+       ibmcam_Packet_Format1(uvd, 0x28, 0x22);
+       ibmcam_Packet_Format1(uvd, light_27, 0);
+       ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
+
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
+
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x30, 0x14);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
+       ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
+       ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
+       ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
+       ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
+       ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
+       ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
+       ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
+       ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
+       ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
+       ibmcam_PacketFormat2(uvd, 0x11, 0xba);
+       ibmcam_PacketFormat2(uvd, 0x12, 0x53);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x16, 0x00);
+       ibmcam_PacketFormat2(uvd, 0x17, 0x28);
+       ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
+       ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x00, 0x18);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x13, 0x18);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x14, 0x06);
+
+       /* This is default brightness */
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x31, 0x37);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x32, 0x46);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x33, 0x55);
+
+       ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x29, 0x80);
+       ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
+       ibmcam_Packet_Format1(uvd, 0x30, 0x17);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x34, 0x00);
+
+       ibmcam_veio(uvd, 0, 0x00, 0x0101);
+       ibmcam_veio(uvd, 0, 0x00, 0x010a);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_veio(uvd, 0, 0x80, 0x0103);
+               ibmcam_veio(uvd, 0, 0x60, 0x0105);
+               ibmcam_veio(uvd, 0, 0x0c, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x0b, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x00, 0x0129);
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
+               ibmcam_veio(uvd, 0, 0x8f, 0x0105);
+               ibmcam_veio(uvd, 0, 0x06, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x0d, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x03, 0x0129);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
+               ibmcam_veio(uvd, 0, 0x90, 0x0105);
+               ibmcam_veio(uvd, 0, 0x02, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x05, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x00, 0x0129);
+               break;
+       }
+
+       ibmcam_veio(uvd, 0, 0xff, 0x012b);
+
+       /* This is another brightness - don't know why */
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
+
+       /* Default contrast */
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
+
+       /* Default sharpness */
+       for (i=0; i < 2; i++)
+               ibmcam_PacketFormat2(uvd, sharp_13, 0x1a);      /* Level 4 FIXME */
+
+       /* Default lighting conditions */
+       ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
+
+       /* Assorted init */
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x36, 0x0102);
+               ibmcam_veio(uvd, 0, 0x1a, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+#if 0
+               ibmcam_veio(uvd, 0, 0x00, 0x0106);
+               ibmcam_veio(uvd, 0, 0x38, 0x0107);
+#else
+               ibmcam_veio(uvd, 0, 0x02, 0x0106);
+               ibmcam_veio(uvd, 0, 0x2a, 0x0107);
+#endif
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x04, 0x0102);
+               ibmcam_veio(uvd, 0, 0x02, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x01, 0x0106);
+               ibmcam_veio(uvd, 0, 0xca, 0x0107);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x08, 0x0102);
+               ibmcam_veio(uvd, 0, 0x01, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2f, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x03, 0x0106);
+               ibmcam_veio(uvd, 0, 0xf6, 0x0107);
+               break;
+       }
+       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
+}
+
+static int ibmcam_model2_setup(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
+       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
+       ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+       ibmcam_veio(uvd, 0, 0x0008, 0x012b);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0090, 0x0107);    /* Unique to every mode*/
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0098, 0x0107);    /* Unique to every mode*/
+               break;
+       case VIDEOSIZE_352x240:
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x00da, 0x0107);    /* Unique to every mode*/
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x00fe, 0x0107);    /* Unique to every mode*/
+               break;
+       }
+       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
+}
+
+/*
+ * ibmcam_model1_setup_after_video_if()
+ *
+ * This code adds finishing touches to the video data interface.
+ * Here we configure the frame rate and turn on the LED.
+ */
+static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
+{
+       unsigned short internal_frame_rate;
+
+       RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+       internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
+       ibmcam_veio(uvd, 0, 0x01, 0x0114);
+       ibmcam_veio(uvd, 0, 0xc0, 0x010c);
+}
+
+static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
+{
+       unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
+
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x0050, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               break;
+       case VIDEOSIZE_320x240:
+       case VIDEOSIZE_352x240:
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x0040, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               break;
+       }
+       ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+       ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+
+       /*
+        * Hardware settings, may affect CMOS sensor; not user controls!
+        * -------------------------------------------------------------
+        * 0x0004: no effect
+        * 0x0006: hardware effect
+        * 0x0008: no effect
+        * 0x000a: stops video stream, probably important h/w setting
+        * 0x000c: changes color in hardware manner (not user setting)
+        * 0x0012: changes number of colors (does not affect speed)
+        * 0x002a: no effect
+        * 0x002c: hardware setting (related to scan lines)
+        * 0x002e: stops video stream, probably important h/w setting
+        */
+       ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
+       ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
+       ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
+       ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
+       ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
+
+       /*
+        * Function 0x0030 pops up all over the place. Apparently
+        * it is a hardware control register, with every bit assigned to
+        * do something.
+        */
+       ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
+
+       /*
+        * Magic control of CMOS sensor. Only lower values like
+        * 0-3 work, and picture shifts left or right. Don't change.
+        */
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
+               break;
+       case VIDEOSIZE_352x240:
+               /* This mode doesn't work as Windows programs it; changed to work */
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
+               break;
+       }
+
+       ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
+
+       /*
+        * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
+        * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
+        * slowest setting. However for all practical reasons high settings make no
+        * sense because USB is not fast enough to support high FPS. Be aware that
+        * the picture datastream will be severely disrupted if you ask for
+        * frame rate faster than allowed for the video size - see below:
+        *
+        * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
+        * -----------------------------------------------------------------
+        * 176x144: [6..31]
+        * 320x240: [8..31]
+        * 352x240: [10..31]
+        * 352x288: [16..31] I have to raise lower threshold for stability...
+        *
+        * As usual, slower FPS provides better sensitivity.
+        */
+       {
+               short hw_fps=31, i_framerate;
+
+               RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+               i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
+               switch (uvd->videosize) {
+               case VIDEOSIZE_176x144:
+                       hw_fps = 6 + i_framerate*4;
+                       break;
+               case VIDEOSIZE_320x240:
+                       hw_fps = 8 + i_framerate*3;
+                       break;
+               case VIDEOSIZE_352x240:
+                       hw_fps = 10 + i_framerate*2;
+                       break;
+               case VIDEOSIZE_352x288:
+                       hw_fps = 28 + i_framerate/2;
+                       break;
+               }
+               if (uvd->debug > 0)
+                       info("Framerate (hardware): %hd.", hw_fps);
+               RESTRICT_TO_RANGE(hw_fps, 0, 31);
+               ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
+       }
+
+       /*
+        * This setting does not visibly affect pictures; left it here
+        * because it was present in Windows USB data stream. This function
+        * does not allow arbitrary values and apparently is a bit mask, to
+        * be activated only at appropriate time. Don't change it randomly!
+        */
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
+               break;
+       case VIDEOSIZE_352x240:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
+               break;
+       }
+
+       ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
+
+       if (init_model2_rg2 >= 0) {
+               RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
+               setup_model2_rg2 = init_model2_rg2;
+       } else
+               setup_model2_rg2 = 0x002f;
+
+       if (init_model2_sat >= 0) {
+               RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
+               setup_model2_sat = init_model2_sat;
+       } else
+               setup_model2_sat = 0x0034;
+
+       if (init_model2_yb >= 0) {
+               RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
+               setup_model2_yb = init_model2_yb;
+       } else
+               setup_model2_yb = 0x00a0;
+
+       ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
+       ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
+       ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
+       ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
+
+       /* Hardware control command */
+       ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
+
+       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go camera, go! */
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+}
+
+static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
+{
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000b, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0025, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0048, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0035, 0x012e);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0048, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0090, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0018, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0007, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0001, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x002a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
+               ibmcam_veio(uvd, 0, 0x006d, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x008c, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0006, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0002, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0025, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0048, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       }
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+}
+
+static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
+{
+       int i;
+       /*
+        * 01.01.08 - Added for RCA video in support -LO
+        * This struct is used to init the Model3 cam to use the RCA video in port
+        * instead of the CCD sensor.
+        */
+       static const struct struct_initData initData[] = {
+               {0, 0x0000, 0x010c},
+               {0, 0x0006, 0x012c},
+               {0, 0x0078, 0x012d},
+               {0, 0x0046, 0x012f},
+               {0, 0xd141, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfea8, 0x0124},
+               {1, 0x0000, 0x0116},
+               {0, 0x0064, 0x0116},
+               {1, 0x0000, 0x0115},
+               {0, 0x0003, 0x0115},
+               {0, 0x0008, 0x0123},
+               {0, 0x0000, 0x0117},
+               {0, 0x0000, 0x0112},
+               {0, 0x0080, 0x0100},
+               {0, 0x0000, 0x0100},
+               {1, 0x0000, 0x0116},
+               {0, 0x0060, 0x0116},
+               {0, 0x0002, 0x0112},
+               {0, 0x0000, 0x0123},
+               {0, 0x0001, 0x0117},
+               {0, 0x0040, 0x0108},
+               {0, 0x0019, 0x012c},
+               {0, 0x0040, 0x0116},
+               {0, 0x000a, 0x0115},
+               {0, 0x000b, 0x0115},
+               {0, 0x0078, 0x012d},
+               {0, 0x0046, 0x012f},
+               {0, 0xd141, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfea8, 0x0124},
+               {0, 0x0064, 0x0116},
+               {0, 0x0000, 0x0115},
+               {0, 0x0001, 0x0115},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00aa, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f2, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x000f, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f8, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00fc, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f9, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x003c, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0027, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0019, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0021, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0006, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0045, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002a, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x000e, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002b, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f4, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002c, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0004, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002d, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0014, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002e, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0003, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002f, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0003, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0014, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0053, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0x0000, 0x0101},
+               {0, 0x00a0, 0x0103},
+               {0, 0x0078, 0x0105},
+               {0, 0x0000, 0x010a},
+               {0, 0x0024, 0x010b},
+               {0, 0x0028, 0x0119},
+               {0, 0x0088, 0x011b},
+               {0, 0x0002, 0x011d},
+               {0, 0x0003, 0x011e},
+               {0, 0x0000, 0x0129},
+               {0, 0x00fc, 0x012b},
+               {0, 0x0008, 0x0102},
+               {0, 0x0000, 0x0104},
+               {0, 0x0008, 0x011a},
+               {0, 0x0028, 0x011c},
+               {0, 0x0021, 0x012a},
+               {0, 0x0000, 0x0118},
+               {0, 0x0000, 0x0132},
+               {0, 0x0000, 0x0109},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0031, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00dc, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0032, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0020, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0030, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0008, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0x0003, 0x0106},
+               {0, 0x0062, 0x0107},
+               {0, 0x0003, 0x0111},
+       };
+#define NUM_INIT_DATA
+
+       unsigned short compression = 0; /* 0=none, 7=best frame rate  */
+       int f_rate; /* 0=Fastest 7=slowest */
+
+       if (IBMCAM_T(uvd)->initialized)
+               return;
+
+       /* Internal frame rate is controlled by f_rate value */
+       f_rate = 7 - framerate;
+       RESTRICT_TO_RANGE(f_rate, 0, 7);
+
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0123);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0117);
+       ibmcam_veio(uvd, 0, 0x0040, 0x0108);
+       ibmcam_veio(uvd, 0, 0x0019, 0x012c);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0115);
+       ibmcam_veio(uvd, 0, 0x0003, 0x0115);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0115);
+       ibmcam_veio(uvd, 0, 0x000b, 0x0115);
+       ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
+       ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
+       ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
+       ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
+       ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
+       ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
+       ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
+       ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
+       ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
+       ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
+       ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
+       ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
+       ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
+       ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
+       ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
+       ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
+       ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
+       ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
+       ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
+       ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
+       ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
+       ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
+       ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
+       ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
+       ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
+       ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
+       ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
+       ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
+       ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
+       ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
+       ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
+       ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
+       ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
+       ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
+       ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
+               ibmcam_veio(uvd, 0, 0x0016, 0x011b);
+               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               ibmcam_veio(uvd, 0, 0x0018, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
+               ibmcam_veio(uvd, 0, 0x0028, 0x011c);
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0118);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
+               ibmcam_veio(uvd, 0, 0x0000, 0x011e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               /* 4 commands from 160x120 skipped */
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
+               ibmcam_veio(uvd, 0, 0x0006, 0x011b);
+               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0010, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
+               ibmcam_veio(uvd, 0, 0x003f, 0x011c);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0118);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
+               break;
+       case VIDEOSIZE_640x480:
+               ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
+               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0101);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
+               break;
+       }
+       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);     /* Hue */
+       ibmcam_model3_Packet1(uvd, 0x0036, 0x0011);     /* Brightness */
+       ibmcam_model3_Packet1(uvd, 0x0060, 0x0002);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0061, 0x0004);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0062, 0x0005);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0063, 0x0014);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
+       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
+       ibmcam_model3_Packet1(uvd, 0x0067, 0x0001);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x005b, 0x000c);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x005c, 0x0016);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x002c, 0x0003);     /* Was 1, broke 640x480 */
+       ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
+       ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
+       ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
+       ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
+       ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
+       ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
+       ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
+       ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
+       ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
+       ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
+       ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
+       ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
+       ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
+       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
+       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
+       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0107);
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0062, 0x0107);
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
+               break;
+       case VIDEOSIZE_640x480:
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);    /* Adjustments */
+               ibmcam_veio(uvd, 0, 0x00b4, 0x0107);    /* Adjustments */
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
+               break;
+       }
+
+       /* 01.01.08 - Added for RCA video in support -LO */
+       if(init_model3_input) {
+               if (debug > 0)
+                       info("Setting input to RCA.");
+               for (i=0; i < ARRAY_SIZE(initData); i++) {
+                       ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
+               }
+       }
+
+       ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+}
+
+/*
+ * ibmcam_video_stop()
+ *
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
+ */
+static void ibmcam_video_stop(struct uvd *uvd)
+{
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_veio(uvd, 0, 0x01, 0x0114);
+               ibmcam_veio(uvd, 0, 0xc0, 0x010c);
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_send_FF_04_02(uvd);
+               ibmcam_veio(uvd, 1, 0x00, 0x0100);
+               ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
+               break;
+       case IBMCAM_MODEL_2:
+case IBMCAM_MODEL_4:
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop the camera */
+
+               ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
+
+               ibmcam_veio(uvd, 0, 0x0080, 0x0100);    /* LED Off */
+               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
+
+               ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
+
+               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
+               break;
+       case IBMCAM_MODEL_3:
+#if 1
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);
+
+               /* Here we are supposed to select video interface alt. setting 0 */
+               ibmcam_veio(uvd, 0, 0x0006, 0x012c);
+
+               ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
+
+               ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+               ibmcam_veio(uvd, 0, 0x0064, 0x0116);
+               ibmcam_veio(uvd, 1, 0x0000, 0x0115);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0115);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0123);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0117);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
+               ibmcam_veio(uvd, 0, 0x0080, 0x0100);
+               IBMCAM_T(uvd)->initialized = 0;
+#endif
+               break;
+       } /* switch */
+}
+
+/*
+ * ibmcam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
+{
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+               if (do_stop)
+                       ibmcam_video_stop(uvd);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_model1_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_2:
+               ibmcam_model2_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_3:
+               ibmcam_video_stop(uvd);
+               ibmcam_model3_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_4:
+               ibmcam_model4_setup_after_video_if(uvd);
+               break;
+       }
+}
+
+static void ibmcam_video_start(struct uvd *uvd)
+{
+       ibmcam_change_lighting_conditions(uvd);
+       ibmcam_set_sharpness(uvd);
+       ibmcam_reinit_iso(uvd, 0);
+}
+
+/*
+ * Return negative code on failure, 0 on success.
+ */
+static int ibmcam_setup_on_open(struct uvd *uvd)
+{
+       int setup_ok = 0; /* Success by default */
+       /* Send init sequence only once, it's large! */
+       if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
+               switch (IBMCAM_T(uvd)->camera_model) {
+               case IBMCAM_MODEL_1:
+                       setup_ok = ibmcam_model1_setup(uvd);
+                       break;
+               case IBMCAM_MODEL_2:
+                       setup_ok = ibmcam_model2_setup(uvd);
+                       break;
+               case IBMCAM_MODEL_3:
+               case IBMCAM_MODEL_4:
+                       /* We do all setup when Isoc stream is requested */
+                       break;
+               }
+               IBMCAM_T(uvd)->initialized = (setup_ok != 0);
+       }
+       return setup_ok;
+}
+
+static void ibmcam_configure_video(struct uvd *uvd)
+{
+       if (uvd == NULL)
+               return;
+
+       RESTRICT_TO_RANGE(init_brightness, 0, 255);
+       RESTRICT_TO_RANGE(init_contrast, 0, 255);
+       RESTRICT_TO_RANGE(init_color, 0, 255);
+       RESTRICT_TO_RANGE(init_hue, 0, 255);
+       RESTRICT_TO_RANGE(hue_correction, 0, 255);
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = init_color << 8;
+       uvd->vpic.hue = init_hue << 8;
+       uvd->vpic.brightness = init_brightness << 8;
+       uvd->vpic.contrast = init_contrast << 8;
+       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "IBM USB Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
+       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
+       uvd->vcap.minwidth = min_canvasWidth;
+       uvd->vcap.minheight = min_canvasHeight;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+}
+
+/*
+ * ibmcam_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like IBM C-it camera.
+ *
+ * History:
+ * 22-Jan-2000 Moved camera init code to ibmcam_open()
+ * 27=Jan-2000 Changed to use static structures, added locking.
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ * 03-Jul-2000 Fixed endianness bug.
+ * 12-Nov-2000 Reworked to comply with new probe() signature.
+ * 23-Jan-2001 Added compatibility with 2.2.x kernels.
+ */
+static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct uvd *uvd = NULL;
+       int ix, i, nas, model=0, canvasX=0, canvasY=0;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
+       unsigned char video_ep = 0;
+
+       if (debug >= 1)
+               info("ibmcam_probe(%p,%u.)", intf, ifnum);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       /* Check the version/revision */
+       switch (le16_to_cpu(dev->descriptor.bcdDevice)) {
+       case 0x0002:
+               if (ifnum != 2)
+                       return -ENODEV;
+               model = IBMCAM_MODEL_1;
+               break;
+       case 0x030A:
+               if (ifnum != 0)
+                       return -ENODEV;
+               if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) ||
+                   (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID))
+                       model = IBMCAM_MODEL_4;
+               else
+                       model = IBMCAM_MODEL_2;
+               break;
+       case 0x0301:
+               if (ifnum != 0)
+                       return -ENODEV;
+               model = IBMCAM_MODEL_3;
+               break;
+       default:
+               err("IBM camera with revision 0x%04x is not supported.",
+                       le16_to_cpu(dev->descriptor.bcdDevice));
+               return -ENODEV;
+       }
+
+       /* Print detailed info on what we found so far */
+       do {
+               char *brand = NULL;
+               switch (le16_to_cpu(dev->descriptor.idProduct)) {
+               case NETCAM_PRODUCT_ID:
+                       brand = "IBM NetCamera";
+                       break;
+               case VEO_800C_PRODUCT_ID:
+                       brand = "Veo Stingray [800C]";
+                       break;
+               case VEO_800D_PRODUCT_ID:
+                       brand = "Veo Stingray [800D]";
+                       break;
+               case IBMCAM_PRODUCT_ID:
+               default:
+                       brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
+                       break;
+               }
+               info("%s USB camera found (model %d, rev. 0x%04x)",
+                    brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
+       } while (0);
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = intf->num_altsetting;
+       if (debug > 0)
+               info("Number of alternate settings=%d.", nas);
+       if (nas < 2) {
+               err("Too few alternate settings for this camera!");
+               return -ENODEV;
+       }
+       /* Validate all alternate settings */
+       for (ix=0; ix < nas; ix++) {
+               const struct usb_host_interface *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &intf->altsetting[ix];
+               i = interface->desc.bAlternateSetting;
+               if (interface->desc.bNumEndpoints != 1) {
+                       err("Interface %d. has %u. endpoints!",
+                           ifnum, (unsigned)(interface->desc.bNumEndpoints));
+                       return -ENODEV;
+               }
+               endpoint = &interface->endpoint[0].desc;
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return -ENODEV;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!", ifnum);
+                       return -ENODEV;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!", ifnum);
+                       return -ENODEV;
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return -ENODEV;
+                       }
+               } else {
+                       if (actInterface < 0) {
+                               actInterface = i;
+                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+                               if (debug > 0)
+                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                       } else
+                               err("More than one active alt. setting! Ignoring #%d.", i);
+               }
+       }
+       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
+               err("Failed to recognize the camera!");
+               return -ENODEV;
+       }
+
+       /* Validate options */
+       switch (model) {
+       case IBMCAM_MODEL_1:
+               RESTRICT_TO_RANGE(lighting, 0, 2);
+               RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
+               if (framerate < 0)
+                       framerate = 2;
+               canvasX = 352;
+               canvasY = 288;
+               break;
+       case IBMCAM_MODEL_2:
+               RESTRICT_TO_RANGE(lighting, 0, 15);
+               RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
+               if (framerate < 0)
+                       framerate = 2;
+               canvasX = 352;
+               canvasY = 240;
+               break;
+       case IBMCAM_MODEL_3:
+               RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
+               switch (size) {
+               case SIZE_160x120:
+                       canvasX = 160;
+                       canvasY = 120;
+                       if (framerate < 0)
+                               framerate = 2;
+                       RESTRICT_TO_RANGE(framerate, 0, 5);
+                       break;
+               default:
+                       info("IBM camera: using 320x240");
+                       size = SIZE_320x240;
+                       /* No break here */
+               case SIZE_320x240:
+                       canvasX = 320;
+                       canvasY = 240;
+                       if (framerate < 0)
+                               framerate = 3;
+                       RESTRICT_TO_RANGE(framerate, 0, 5);
+                       break;
+               case SIZE_640x480:
+                       canvasX = 640;
+                       canvasY = 480;
+                       framerate = 0;  /* Slowest, and maybe even that is too fast */
+                       break;
+               }
+               break;
+       case IBMCAM_MODEL_4:
+               RESTRICT_TO_RANGE(lighting, 0, 2);
+               switch (size) {
+               case SIZE_128x96:
+                       canvasX = 128;
+                       canvasY = 96;
+                       break;
+               case SIZE_160x120:
+                       canvasX = 160;
+                       canvasY = 120;
+                       break;
+               default:
+                       info("IBM NetCamera: using 176x144");
+                       size = SIZE_176x144;
+                       /* No break here */
+               case SIZE_176x144:
+                       canvasX = 176;
+                       canvasY = 144;
+                       break;
+               case SIZE_320x240:
+                       canvasX = 320;
+                       canvasY = 240;
+                       break;
+               case SIZE_352x288:
+                       canvasX = 352;
+                       canvasY = 288;
+                       break;
+               }
+               break;
+       default:
+               err("IBM camera: Model %d. not supported!", model);
+               return -ENODEV;
+       }
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               /* Here uvd is a fully allocated uvd object */
+               uvd->flags = flags;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = ifnum;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+               uvd->canvas = VIDEOSIZE(canvasX, canvasY);
+               uvd->videosize = ibmcam_size_to_videosize(size);
+
+               /* Initialize ibmcam-specific data */
+               assert(IBMCAM_T(uvd) != NULL);
+               IBMCAM_T(uvd)->camera_model = model;
+               IBMCAM_T(uvd)->initialized = 0;
+
+               ibmcam_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+       }
+       usb_set_intfdata (intf, uvd);
+       return 0;
+}
+
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },        /* Model 1 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 2 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },        /* Model 3 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 4 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 2 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 4 */
+       { }  /* Terminating entry */
+};
+
+/*
+ * ibmcam_init()
+ *
+ * This code is run to initialize the driver.
+ *
+ * History:
+ * 1/27/00  Reworked to use statically allocated ibmcam structures.
+ * 21/10/00 Completely redesigned to use usbvideo services.
+ */
+static int __init ibmcam_init(void)
+{
+       struct usbvideo_cb cbTbl;
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = ibmcam_probe;
+       cbTbl.setupOnOpen = ibmcam_setup_on_open;
+       cbTbl.videoStart = ibmcam_video_start;
+       cbTbl.videoStop = ibmcam_video_stop;
+       cbTbl.processData = ibmcam_ProcessIsocData;
+       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+       cbTbl.adjustPicture = ibmcam_adjust_picture;
+       cbTbl.getFPS = ibmcam_calculate_fps;
+       return usbvideo_register(
+               &cams,
+               MAX_IBMCAM,
+               sizeof(ibmcam_t),
+               "ibmcam",
+               &cbTbl,
+               THIS_MODULE,
+               id_table);
+}
+
+static void __exit ibmcam_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+module_init(ibmcam_init);
+module_exit(ibmcam_cleanup);
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
new file mode 100644 (file)
index 0000000..c11f5d4
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ * konicawc.c - konica webcam driver
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ * Driver for USB webcams based on Konica chipset. This
+ * chipset is used in Intel YC76 camera.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb_input.h>
+
+#include "usbvideo.h"
+
+#define MAX_BRIGHTNESS 108
+#define MAX_CONTRAST   108
+#define MAX_SATURATION 108
+#define MAX_SHARPNESS  108
+#define MAX_WHITEBAL   372
+#define MAX_SPEED      6
+
+
+#define MAX_CAMERAS    1
+
+#define DRIVER_VERSION "v1.4"
+#define DRIVER_DESC    "Konica Webcam driver"
+
+enum ctrl_req {
+       SetWhitebal     = 0x01,
+       SetBrightness   = 0x02,
+       SetSharpness    = 0x03,
+       SetContrast     = 0x04,
+       SetSaturation   = 0x05,
+};
+
+
+enum frame_sizes {
+       SIZE_160X120    = 0,
+       SIZE_160X136    = 1,
+       SIZE_176X144    = 2,
+       SIZE_320X240    = 3,
+
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+static struct usbvideo *cams;
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+       if (n <= debug) {        \
+               printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+       }
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+
+/* Some default values for initial camera settings,
+   can be set by modprobe */
+
+static int size;
+static int speed = 6;          /* Speed (fps) 0 (slowest) to 6 (fastest) */
+static int brightness =        MAX_BRIGHTNESS/2;
+static int contrast =  MAX_CONTRAST/2;
+static int saturation =        MAX_SATURATION/2;
+static int sharpness = MAX_SHARPNESS/2;
+static int whitebal =  3*(MAX_WHITEBAL/4);
+
+static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
+
+/* These FPS speeds are from the windows config box. They are
+ * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
+ * real fps.
+ */
+
+static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+                              { 24, 40, 48, 60, 72, 80, 100 },
+                              { 18, 30, 36, 45, 54, 60, 75  },
+                              { 6,  10, 12, 15, 18, 21, 25  } };
+
+struct cam_size {
+       u16     width;
+       u16     height;
+       u8      cmd;
+};
+
+static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
+                                         { 160, 136, 0xa },
+                                         { 176, 144, 0x4 },
+                                         { 320, 240, 0x5 } };
+
+struct konicawc {
+       u8 brightness;          /* camera uses 0 - 9, x11 for real value */
+       u8 contrast;            /* as above */
+       u8 saturation;          /* as above */
+       u8 sharpness;           /* as above */
+       u8 white_bal;           /* 0 - 33, x11 for real value */
+       u8 speed;               /* Stored as 0 - 6, used as index in spd_to_* (above) */
+       u8 size;                /* Frame Size */
+       int height;
+       int width;
+       struct urb *sts_urb[USBVIDEO_NUMSBUF];
+       u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
+       struct urb *last_data_urb;
+       int lastframe;
+       int cur_frame_size;     /* number of bytes in current frame size */
+       int maxline;            /* number of lines per frame */
+       int yplanesz;           /* Number of bytes in the Y plane */
+       unsigned int buttonsts:1;
+#ifdef CONFIG_INPUT
+       struct input_dev *input;
+       char input_physname[64];
+#endif
+};
+
+
+#define konicawc_set_misc(uvd, req, value, index)              konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
+#define konicawc_get_misc(uvd, req, value, index, buf, sz)     konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
+#define konicawc_set_value(uvd, value, index)                  konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
+
+
+static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
+{
+       int retval = usb_control_msg(uvd->dev,
+               dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
+                   request, 0x40 | dir, value, index, buf, len, 1000);
+       return retval < 0 ? retval : 0;
+}
+
+
+static inline void konicawc_camera_on(struct uvd *uvd)
+{
+       DEBUG(0, "camera on");
+       konicawc_set_misc(uvd, 0x2, 1, 0x0b);
+}
+
+
+static inline void konicawc_camera_off(struct uvd *uvd)
+{
+       DEBUG(0, "camera off");
+       konicawc_set_misc(uvd, 0x2, 0, 0x0b);
+}
+
+
+static void konicawc_set_camera_size(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
+       cam->width = camera_sizes[cam->size].width;
+       cam->height = camera_sizes[cam->size].height;
+       cam->yplanesz = cam->height * cam->width;
+       cam->cur_frame_size = (cam->yplanesz * 3) / 2;
+       cam->maxline = cam->yplanesz / 256;
+       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+}
+
+
+static int konicawc_setup_on_open(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+           cam->brightness * 11);
+       konicawc_set_value(uvd, cam->brightness, SetBrightness);
+       DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
+           cam->white_bal * 11);
+       konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
+       DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+           cam->contrast * 11);
+       konicawc_set_value(uvd, cam->contrast, SetContrast);
+       DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
+           cam->saturation * 11);
+       konicawc_set_value(uvd, cam->saturation, SetSaturation);
+       DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
+           cam->sharpness * 11);
+       konicawc_set_value(uvd, cam->sharpness, SetSharpness);
+       konicawc_set_camera_size(uvd);
+       cam->lastframe = -2;
+       cam->buttonsts = 0;
+       return 0;
+}
+
+
+static void konicawc_adjust_picture(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       konicawc_camera_off(uvd);
+       DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
+       uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
+       if(cam->brightness != uvd->vpic.brightness / 11) {
+          cam->brightness = uvd->vpic.brightness / 11;
+          DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+              cam->brightness * 11);
+          konicawc_set_value(uvd, cam->brightness, SetBrightness);
+       }
+
+       DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
+       uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
+       if(cam->contrast != uvd->vpic.contrast / 11) {
+               cam->contrast = uvd->vpic.contrast / 11;
+               DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+                   cam->contrast * 11);
+               konicawc_set_value(uvd, cam->contrast, SetContrast);
+       }
+       konicawc_camera_on(uvd);
+}
+
+#ifdef CONFIG_INPUT
+
+static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
+{
+       struct input_dev *input_dev;
+
+       usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+       strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+
+       cam->input = input_dev = input_allocate_device();
+       if (!input_dev) {
+               warn("Not enough memory for camera's input device\n");
+               return;
+       }
+
+       input_dev->name = "Konicawc snapshot button";
+       input_dev->phys = cam->input_physname;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->cdev.dev = &dev->dev;
+
+       input_dev->evbit[0] = BIT(EV_KEY);
+       input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+       input_dev->private = cam;
+
+       input_register_device(cam->input);
+}
+
+static void konicawc_unregister_input(struct konicawc *cam)
+{
+       if (cam->input) {
+               input_unregister_device(cam->input);
+               cam->input = NULL;
+       }
+}
+
+static void konicawc_report_buttonstat(struct konicawc *cam)
+{
+       if (cam->input) {
+               input_report_key(cam->input, BTN_0, cam->buttonsts);
+               input_sync(cam->input);
+       }
+}
+
+#else
+
+static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }
+static inline void konicawc_unregister_input(struct konicawc *cam) { }
+static inline void konicawc_report_buttonstat(struct konicawc *cam) { }
+
+#endif /* CONFIG_INPUT */
+
+static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
+{
+       char *cdata;
+       int i, totlen = 0;
+       unsigned char *status = stsurb->transfer_buffer;
+       int keep = 0, discard = 0, bad = 0;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       for (i = 0; i < dataurb->number_of_packets; i++) {
+               int button = cam->buttonsts;
+               unsigned char sts;
+               int n = dataurb->iso_frame_desc[i].actual_length;
+               int st = dataurb->iso_frame_desc[i].status;
+               cdata = dataurb->transfer_buffer +
+                       dataurb->iso_frame_desc[i].offset;
+
+               /* Detect and ignore errored packets */
+               if (st < 0) {
+                       DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
+                             i, n, st);
+                       uvd->stats.iso_err_count++;
+                       continue;
+               }
+
+               /* Detect and ignore empty packets */
+               if (n <= 0) {
+                       uvd->stats.iso_skip_count++;
+                       continue;
+               }
+
+               /* See what the status data said about the packet */
+               sts = *(status+stsurb->iso_frame_desc[i].offset);
+
+               /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
+                * otherwise:
+                * bit 0 0: keep packet
+                *       1: drop packet (padding data)
+                *
+                * bit 4 0 button not clicked
+                *       1 button clicked
+                * button is used to `take a picture' (in software)
+                */
+
+               if(sts < 0x80) {
+                       button = !!(sts & 0x40);
+                       sts &= ~0x40;
+               }
+
+               /* work out the button status, but don't do
+                  anything with it for now */
+
+               if(button != cam->buttonsts) {
+                       DEBUG(2, "button: %sclicked", button ? "" : "un");
+                       cam->buttonsts = button;
+                       konicawc_report_buttonstat(cam);
+               }
+
+               if(sts == 0x01) { /* drop frame */
+                       discard++;
+                       continue;
+               }
+
+               if((sts > 0x01) && (sts < 0x80)) {
+                       info("unknown status %2.2x", sts);
+                       bad++;
+                       continue;
+               }
+               if(!sts && cam->lastframe == -2) {
+                       DEBUG(2, "dropping frame looking for image start");
+                       continue;
+               }
+
+               keep++;
+               if(sts & 0x80) { /* frame start */
+                       unsigned char marker[] = { 0, 0xff, 0, 0x00 };
+
+                       if(cam->lastframe == -2) {
+                               DEBUG(2, "found initial image");
+                               cam->lastframe = -1;
+                       }
+
+                       marker[3] = sts & 0x7F;
+                       RingQueue_Enqueue(&uvd->dp, marker, 4);
+                       totlen += 4;
+               }
+
+               totlen += n;    /* Little local accounting */
+               RingQueue_Enqueue(&uvd->dp, cdata, n);
+       }
+       DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
+                   keep, discard, bad, totlen);
+       return totlen;
+}
+
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+       int i, ret;
+       for (i = 0; i < FRAMES_PER_DESC; i++) {
+               urb->iso_frame_desc[i].status = 0;
+       }
+       urb->dev = uvd->dev;
+       urb->status = 0;
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
+       if(ret)
+               err("usb_submit_urb error (%d)", ret);
+
+}
+
+
+static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct uvd *uvd = urb->context;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       /* We don't want to do anything if we are about to be removed! */
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return;
+
+       if (!uvd->streaming) {
+               DEBUG(1, "Not streaming, but interrupt!");
+               return;
+       }
+
+       DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
+
+       uvd->stats.urb_count++;
+
+       if (urb->transfer_buffer_length > 32) {
+               cam->last_data_urb = urb;
+               return;
+       }
+       /* Copy the data received into ring queue */
+       if(cam->last_data_urb) {
+               int len = 0;
+               if(urb->start_frame != cam->last_data_urb->start_frame)
+                       err("Lost sync on frames");
+               else if (!urb->status && !cam->last_data_urb->status)
+                       len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
+
+               resubmit_urb(uvd, cam->last_data_urb);
+               resubmit_urb(uvd, urb);
+               cam->last_data_urb = NULL;
+               uvd->stats.urb_length = len;
+               uvd->stats.data_count += len;
+               if(len)
+                       RingQueue_WakeUpInterruptible(&uvd->dp);
+               return;
+       }
+       return;
+}
+
+
+static int konicawc_start_data(struct uvd *uvd)
+{
+       struct usb_device *dev = uvd->dev;
+       int i, errFlag;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       int pktsz;
+       struct usb_interface *intf;
+       struct usb_host_interface *interface = NULL;
+
+       intf = usb_ifnum_to_if(dev, uvd->iface);
+       if (intf)
+               interface = usb_altnum_to_altsetting(intf,
+                               spd_to_iface[cam->speed]);
+       if (!interface)
+               return -ENXIO;
+       pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize);
+       DEBUG(1, "pktsz = %d", pktsz);
+       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+               err("Camera is not operational");
+               return -EFAULT;
+       }
+       uvd->curframe = -1;
+       konicawc_camera_on(uvd);
+       /* Alternate interface 1 is is the biggest frame size */
+       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
+       if (i < 0) {
+               err("usb_set_interface error");
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+
+       /* We double buffer the Iso lists */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               int j, k;
+               struct urb *urb = uvd->sbuf[i].urb;
+               urb->dev = dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = uvd->sbuf[i].data;
+               urb->complete = konicawc_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+               for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = pktsz;
+               }
+
+               urb = cam->sts_urb[i];
+               urb->dev = dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = cam->sts_buf[i];
+               urb->complete = konicawc_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = FRAMES_PER_DESC;
+               for (j=0; j < FRAMES_PER_DESC; j++) {
+                       urb->iso_frame_desc[j].offset = j;
+                       urb->iso_frame_desc[j].length = 1;
+               }
+       }
+
+       cam->last_data_urb = NULL;
+
+       /* Submit all URBs */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
+               if (errFlag)
+                       err("usb_submit_isoc(%d) ret %d", i, errFlag);
+
+               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+               if (errFlag)
+                       err ("usb_submit_isoc(%d) ret %d", i, errFlag);
+       }
+
+       uvd->streaming = 1;
+       DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
+       return 0;
+}
+
+
+static void konicawc_stop_data(struct uvd *uvd)
+{
+       int i, j;
+       struct konicawc *cam;
+
+       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+               return;
+
+       konicawc_camera_off(uvd);
+       uvd->streaming = 0;
+       cam = (struct konicawc *)uvd->user_data;
+       cam->last_data_urb = NULL;
+
+       /* Unschedule all of the iso td's */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               usb_kill_urb(uvd->sbuf[i].urb);
+               usb_kill_urb(cam->sts_urb[i]);
+       }
+
+       if (!uvd->remove_pending) {
+               /* Set packet size to 0 */
+               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
+               if (j < 0) {
+                       err("usb_set_interface() error %d.", j);
+                       uvd->last_error = j;
+               }
+       }
+}
+
+
+static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       int maxline = cam->maxline;
+       int yplanesz = cam->yplanesz;
+
+       assert(frame != NULL);
+
+       DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
+       DEBUG(3, "Frame state = %d", frame->scanstate);
+
+       if(frame->scanstate == ScanState_Scanning) {
+               int drop = 0;
+               int curframe;
+               int fdrops = 0;
+               DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
+               while(RingQueue_GetLength(&uvd->dp) >= 4) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
+                               curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               if(cam->lastframe >= 0) {
+                                       fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
+                                       fdrops--;
+                                       if(fdrops) {
+                                               info("Dropped %d frames (%d -> %d)", fdrops,
+                                                    cam->lastframe, curframe);
+                                       }
+                               }
+                               cam->lastframe = curframe;
+                               frame->curline = 0;
+                               frame->scanstate = ScanState_Lines;
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+                               break;
+                       }
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+                       drop++;
+               }
+               if(drop)
+                       DEBUG(2, "dropped %d bytes looking for new frame", drop);
+       }
+
+       if(frame->scanstate == ScanState_Scanning)
+               return;
+
+       /* Try to move data from queue into frame buffer
+        * We get data in blocks of 384 bytes made up of:
+        * 256 Y, 64 U, 64 V.
+        * This needs to be written out as a Y plane, a U plane and a V plane.
+        */
+
+       while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
+               /* Y */
+               RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
+               /* U */
+               RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
+               /* V */
+               RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
+               frame->seqRead_Length += 384;
+               frame->curline++;
+       }
+       /* See if we filled the frame */
+       if (frame->curline == maxline) {
+               DEBUG(5, "got whole frame");
+
+               frame->frameState = FrameState_Done_Hold;
+               frame->curline = 0;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+
+static int konicawc_find_fps(int size, int fps)
+{
+       int i;
+
+       fps *= 3;
+       DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
+       if(fps <= spd_to_fps[size][0])
+               return 0;
+
+       if(fps >= spd_to_fps[size][MAX_SPEED])
+               return MAX_SPEED;
+
+       for(i = 0; i < MAX_SPEED; i++) {
+               if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
+                       DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
+                       if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
+                               return i;
+                       else
+                               return i+1;
+               }
+       }
+       return MAX_SPEED+1;
+}
+
+
+static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       int newspeed = cam->speed;
+       int newsize;
+       int x = vw->width;
+       int y = vw->height;
+       int fps = vw->flags;
+
+       if(x > 0 && y > 0) {
+               DEBUG(2, "trying to find size %d,%d", x, y);
+               for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+                       if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
+                               break;
+               }
+       } else {
+               newsize = cam->size;
+       }
+
+       if(newsize > MAX_FRAME_SIZE) {
+               DEBUG(1, "couldn't find size %d,%d", x, y);
+               return -EINVAL;
+       }
+
+       if(fps > 0) {
+               DEBUG(1, "trying to set fps to %d", fps);
+               newspeed = konicawc_find_fps(newsize, fps);
+               DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
+       }
+
+       if(newspeed > MAX_SPEED)
+               return -EINVAL;
+
+       DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
+       if((newsize == cam->size) && (newspeed == cam->speed)) {
+               DEBUG(1, "Nothing to do");
+               return 0;
+       }
+       DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
+            camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
+
+       konicawc_stop_data(uvd);
+       uvd->ifaceAltActive = spd_to_iface[newspeed];
+       DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
+       cam->speed = newspeed;
+
+       if(cam->size != newsize) {
+               cam->size = newsize;
+               konicawc_set_camera_size(uvd);
+       }
+
+       /* Flush the input queue and clear any current frame in progress */
+
+       RingQueue_Flush(&uvd->dp);
+       cam->lastframe = -2;
+       if(uvd->curframe != -1) {
+               uvd->frame[uvd->curframe].curline = 0;
+               uvd->frame[uvd->curframe].seqRead_Length = 0;
+               uvd->frame[uvd->curframe].seqRead_Index = 0;
+       }
+
+       konicawc_start_data(uvd);
+       return 0;
+}
+
+
+static int konicawc_calculate_fps(struct uvd *uvd)
+{
+       struct konicawc *cam = uvd->user_data;
+       return spd_to_fps[cam->size][cam->speed]/3;
+}
+
+
+static void konicawc_configure_video(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       u8 buf[2];
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
+       RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
+       RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
+       RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
+       RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
+
+       cam->brightness = brightness / 11;
+       cam->contrast = contrast / 11;
+       cam->saturation = saturation / 11;
+       cam->sharpness = sharpness / 11;
+       cam->white_bal = whitebal / 11;
+
+       uvd->vpic.colour = 108;
+       uvd->vpic.hue = 108;
+       uvd->vpic.brightness = brightness;
+       uvd->vpic.contrast = contrast;
+       uvd->vpic.whiteness = whitebal;
+       uvd->vpic.depth = 6;
+       uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "Konica Webcam");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+       uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+       uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+       uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0 ;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+
+       /* Talk to device */
+       DEBUG(1, "device init");
+       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+       if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
+               DEBUG(2, "2,0,d failed");
+       DEBUG(1, "setting initial values");
+}
+
+static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct uvd *uvd = NULL;
+       int ix, i, nas;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       unsigned char video_ep = 0;
+
+       DEBUG(1, "konicawc_probe(%p)", intf);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice));
+       RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = intf->num_altsetting;
+       if (nas != 8) {
+               err("Incorrect number of alternate settings (%d) for this camera!", nas);
+               return -ENODEV;
+       }
+       /* Validate all alternate settings */
+       for (ix=0; ix < nas; ix++) {
+               const struct usb_host_interface *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &intf->altsetting[ix];
+               i = interface->desc.bAlternateSetting;
+               if (interface->desc.bNumEndpoints != 2) {
+                       err("Interface %d. has %u. endpoints!",
+                           interface->desc.bInterfaceNumber,
+                           (unsigned)(interface->desc.bNumEndpoints));
+                       return -ENODEV;
+               }
+               endpoint = &interface->endpoint[1].desc;
+               DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
+                   endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize));
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return -ENODEV;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return -ENODEV;
+                       }
+               } else {
+                       if (i == spd_to_iface[speed]) {
+                               /* This one is the requested one */
+                               actInterface = i;
+                       }
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS)
+                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+       }
+       if(actInterface == -1) {
+               err("Cant find required endpoint");
+               return -ENODEV;
+       }
+
+       DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               struct konicawc *cam = (struct konicawc *)(uvd->user_data);
+               /* Here uvd is a fully allocated uvd object */
+               for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
+                       cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+                       if(cam->sts_urb[i] == NULL) {
+                               while(i--) {
+                                       usb_free_urb(cam->sts_urb[i]);
+                               }
+                               err("can't allocate urbs");
+                               return -ENOMEM;
+                       }
+               }
+               cam->speed = speed;
+               RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+               cam->width = camera_sizes[size].width;
+               cam->height = camera_sizes[size].height;
+               cam->size = size;
+
+               uvd->flags = 0;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
+               uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
+               uvd->canvas = VIDEOSIZE(320, 240);
+               uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+               /* Initialize konicawc specific data */
+               konicawc_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               uvd->max_frame_size = (320 * 240 * 3)/2;
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+
+               konicawc_register_input(cam, dev);
+       }
+
+       if (uvd) {
+               usb_set_intfdata (intf, uvd);
+               return 0;
+       }
+       return -EIO;
+}
+
+
+static void konicawc_free_uvd(struct uvd *uvd)
+{
+       int i;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       konicawc_unregister_input(cam);
+
+       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
+               usb_free_urb(cam->sts_urb[i]);
+               cam->sts_urb[i] = NULL;
+       }
+}
+
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
+       { }  /* Terminating entry */
+};
+
+
+static int __init konicawc_init(void)
+{
+       struct usbvideo_cb cbTbl;
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = konicawc_probe;
+       cbTbl.setupOnOpen = konicawc_setup_on_open;
+       cbTbl.processData = konicawc_process_isoc;
+       cbTbl.getFPS = konicawc_calculate_fps;
+       cbTbl.setVideoMode = konicawc_set_video_mode;
+       cbTbl.startDataPump = konicawc_start_data;
+       cbTbl.stopDataPump = konicawc_stop_data;
+       cbTbl.adjustPicture = konicawc_adjust_picture;
+       cbTbl.userFree = konicawc_free_uvd;
+       return usbvideo_register(
+               &cams,
+               MAX_CAMERAS,
+               sizeof(struct konicawc),
+               "konicawc",
+               &cbTbl,
+               THIS_MODULE,
+               id_table);
+}
+
+
+static void __exit konicawc_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+module_param(speed, int, 0);
+MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
+module_param(saturation, int, 0);
+MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
+module_param(sharpness, int, 0);
+MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
+module_param(whitebal, int, 0);
+MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(konicawc_init);
+module_exit(konicawc_cleanup);
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
new file mode 100644 (file)
index 0000000..10c58b4
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * USB NB Camera driver
+ *
+ * HISTORY:
+ * 25-Dec-2002 Dmitri      Removed lighting, sharpness parameters, methods.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "usbvideo.h"
+
+#define        ULTRACAM_VENDOR_ID      0x0461
+#define        ULTRACAM_PRODUCT_ID     0x0813
+
+#define MAX_CAMERAS            4       /* How many devices we allow to connect */
+
+/*
+ * This structure lives in uvd_t->user field.
+ */
+typedef struct {
+       int initialized;        /* Had we already sent init sequence? */
+       int camera_model;       /* What type of IBM camera we got? */
+       int has_hdr;
+} ultracam_t;
+#define        ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
+
+static struct usbvideo *cams = NULL;
+
+static int debug = 0;
+
+static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+static const int min_canvasWidth  = 8;
+static const int min_canvasHeight = 4;
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  6
+static int framerate = -1;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+static int hue_correction = 128;
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+module_param(flags, int, 0);
+MODULE_PARM_DESC(flags,
+               "Bitfield: 0=VIDIOCSYNC, "
+               "1=B/W, "
+               "2=show hints, "
+               "3=show stats, "
+               "4=test pattern, "
+               "5=separate frames, "
+               "6=clean frames");
+module_param(framerate, int, 0);
+MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
+
+module_param(init_brightness, int, 0);
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
+module_param(init_contrast, int, 0);
+MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
+module_param(init_color, int, 0);
+MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
+module_param(init_hue, int, 0);
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
+module_param(hue_correction, int, 0);
+MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
+
+/*
+ * ultracam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ultracam_find_header() or ultracam_parse_lines() to do most
+ * of work.
+ *
+ * 02-Nov-2000 First (mostly dummy) version.
+ * 06-Nov-2000 Rewrote to dump all data into frame.
+ */
+static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       int n;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+
+       /* Try to move data from queue into frame buffer */
+       n = RingQueue_GetLength(&uvd->dp);
+       if (n > 0) {
+               int m;
+               /* See how much spare we have left */
+               m = uvd->max_frame_size - frame->seqRead_Length;
+               if (n > m)
+                       n = m;
+               /* Now move that much data into frame buffer */
+               RingQueue_Dequeue(
+                       &uvd->dp,
+                       frame->data + frame->seqRead_Length,
+                       m);
+               frame->seqRead_Length += m;
+       }
+       /* See if we filled the frame */
+       if (frame->seqRead_Length >= uvd->max_frame_size) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+/*
+ * ultracam_veio()
+ *
+ * History:
+ * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
+ */
+static int ultracam_veio(
+       struct uvd *uvd,
+       unsigned char req,
+       unsigned short value,
+       unsigned short index,
+       int is_out)
+{
+       static const char proc[] = "ultracam_veio";
+       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+       int i;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return 0;
+
+       if (!is_out) {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_rcvctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       cp,
+                       sizeof(cp),
+                       1000);
+#if 1
+               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x)",
+                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                      req, value, index);
+#endif
+       } else {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_sndctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       1000);
+       }
+       if (i < 0) {
+               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
+                   proc, i);
+               uvd->last_error = i;
+       }
+       return i;
+}
+
+/*
+ * ultracam_calculate_fps()
+ */
+static int ultracam_calculate_fps(struct uvd *uvd)
+{
+       return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * ultracam_adjust_contrast()
+ */
+static void ultracam_adjust_contrast(struct uvd *uvd)
+{
+}
+
+/*
+ * ultracam_set_brightness()
+ *
+ * This procedure changes brightness of the picture.
+ */
+static void ultracam_set_brightness(struct uvd *uvd)
+{
+}
+
+static void ultracam_set_hue(struct uvd *uvd)
+{
+}
+
+/*
+ * ultracam_adjust_picture()
+ *
+ * This procedure gets called from V4L interface to update picture settings.
+ * Here we change brightness and contrast.
+ */
+static void ultracam_adjust_picture(struct uvd *uvd)
+{
+       ultracam_adjust_contrast(uvd);
+       ultracam_set_brightness(uvd);
+       ultracam_set_hue(uvd);
+}
+
+/*
+ * ultracam_video_stop()
+ *
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
+ */
+static void ultracam_video_stop(struct uvd *uvd)
+{
+}
+
+/*
+ * ultracam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ */
+static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
+{
+}
+
+static void ultracam_video_start(struct uvd *uvd)
+{
+       ultracam_reinit_iso(uvd, 0);
+}
+
+static int ultracam_resetPipe(struct uvd *uvd)
+{
+       usb_clear_halt(uvd->dev, uvd->video_endp);
+       return 0;
+}
+
+static int ultracam_alternateSetting(struct uvd *uvd, int setting)
+{
+       static const char proc[] = "ultracam_alternateSetting";
+       int i;
+       i = usb_set_interface(uvd->dev, uvd->iface, setting);
+       if (i < 0) {
+               err("%s: usb_set_interface error", proc);
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+       return 0;
+}
+
+/*
+ * Return negative code on failure, 0 on success.
+ */
+static int ultracam_setup_on_open(struct uvd *uvd)
+{
+       int setup_ok = 0; /* Success by default */
+       /* Send init sequence only once, it's large! */
+       if (!ULTRACAM_T(uvd)->initialized) {
+               ultracam_alternateSetting(uvd, 0x04);
+               ultracam_alternateSetting(uvd, 0x00);
+               ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
+               ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
+               ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
+               ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
+               ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
+               ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
+               ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
+               ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
+               ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
+               ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
+               ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
+               ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
+               ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
+               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
+               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
+               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
+               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
+               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
+               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
+               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
+               ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
+               ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
+               ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
+               ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
+               ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
+               ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
+               ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
+               ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
+               ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
+               ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
+               ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
+               ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
+               ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
+               ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
+               ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
+               ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
+               ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
+               ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
+               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
+               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
+               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
+               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
+               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
+               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
+               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
+               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
+               ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
+               ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
+               ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
+               ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
+               ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
+               ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
+               ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_alternateSetting(uvd, 0x04);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
+               ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
+               ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
+               ultracam_resetPipe(uvd);
+               ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
+       }
+       return setup_ok;
+}
+
+static void ultracam_configure_video(struct uvd *uvd)
+{
+       if (uvd == NULL)
+               return;
+
+       RESTRICT_TO_RANGE(init_brightness, 0, 255);
+       RESTRICT_TO_RANGE(init_contrast, 0, 255);
+       RESTRICT_TO_RANGE(init_color, 0, 255);
+       RESTRICT_TO_RANGE(init_hue, 0, 255);
+       RESTRICT_TO_RANGE(hue_correction, 0, 255);
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = init_color << 8;
+       uvd->vpic.hue = init_hue << 8;
+       uvd->vpic.brightness = init_brightness << 8;
+       uvd->vpic.contrast = init_contrast << 8;
+       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "IBM Ultra Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
+       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
+       uvd->vcap.minwidth = min_canvasWidth;
+       uvd->vcap.minheight = min_canvasHeight;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+}
+
+/*
+ * ultracam_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like our camera.
+ *
+ * History:
+ * 12-Nov-2000 Reworked to comply with new probe() signature.
+ * 23-Jan-2001 Added compatibility with 2.2.x kernels.
+ */
+static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct uvd *uvd = NULL;
+       int ix, i, nas;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       unsigned char video_ep = 0;
+
+       if (debug >= 1)
+               info("ultracam_probe(%p)", intf);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       info("IBM Ultra camera found (rev. 0x%04x)",
+               le16_to_cpu(dev->descriptor.bcdDevice));
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = intf->num_altsetting;
+       if (debug > 0)
+               info("Number of alternate settings=%d.", nas);
+       if (nas < 8) {
+               err("Too few alternate settings for this camera!");
+               return -ENODEV;
+       }
+       /* Validate all alternate settings */
+       for (ix=0; ix < nas; ix++) {
+               const struct usb_host_interface *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &intf->altsetting[ix];
+               i = interface->desc.bAlternateSetting;
+               if (interface->desc.bNumEndpoints != 1) {
+                       err("Interface %d. has %u. endpoints!",
+                           interface->desc.bInterfaceNumber,
+                           (unsigned)(interface->desc.bNumEndpoints));
+                       return -ENODEV;
+               }
+               endpoint = &interface->endpoint[0].desc;
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return -ENODEV;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return -ENODEV;
+                       }
+               } else {
+                       if (actInterface < 0) {
+                               actInterface = i;
+                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+                               if (debug > 0)
+                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                       } else {
+                               /* Got another active alt. setting */
+                               if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
+                                       /* This one is better! */
+                                       actInterface = i;
+                                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+                                       if (debug > 0) {
+                                               info("Even better ctive setting=%d. maxPS=%d.",
+                                                    i, maxPS);
+                                       }
+                               }
+                       }
+               }
+       }
+       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
+               err("Failed to recognize the camera!");
+               return -ENODEV;
+       }
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               /* Here uvd is a fully allocated uvd object */
+               uvd->flags = flags;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+               uvd->canvas = VIDEOSIZE(640, 480);      /* FIXME */
+               uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
+
+               /* Initialize ibmcam-specific data */
+               assert(ULTRACAM_T(uvd) != NULL);
+               ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
+               ULTRACAM_T(uvd)->initialized = 0;
+
+               ultracam_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+       }
+
+       if (uvd) {
+               usb_set_intfdata (intf, uvd);
+               return 0;
+       }
+       return -EIO;
+}
+
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
+       { }  /* Terminating entry */
+};
+
+/*
+ * ultracam_init()
+ *
+ * This code is run to initialize the driver.
+ */
+static int __init ultracam_init(void)
+{
+       struct usbvideo_cb cbTbl;
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = ultracam_probe;
+       cbTbl.setupOnOpen = ultracam_setup_on_open;
+       cbTbl.videoStart = ultracam_video_start;
+       cbTbl.videoStop = ultracam_video_stop;
+       cbTbl.processData = ultracam_ProcessIsocData;
+       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+       cbTbl.adjustPicture = ultracam_adjust_picture;
+       cbTbl.getFPS = ultracam_calculate_fps;
+       return usbvideo_register(
+               &cams,
+               MAX_CAMERAS,
+               sizeof(ultracam_t),
+               "ultracam",
+               &cbTbl,
+               THIS_MODULE,
+               id_table);
+}
+
+static void __exit ultracam_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+MODULE_DEVICE_TABLE(usb, id_table);
+MODULE_LICENSE("GPL");
+
+module_init(ultracam_init);
+module_exit(ultracam_cleanup);
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
new file mode 100644 (file)
index 0000000..13b37c8
--- /dev/null
@@ -0,0 +1,2190 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+
+#include "usbvideo.h"
+
+#if defined(MAP_NR)
+#define        virt_to_page(v) MAP_NR(v)       /* Kernels 2.2.x */
+#endif
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+
+/*
+ * Local prototypes.
+ */
+static void usbvideo_Disconnect(struct usb_interface *intf);
+static void usbvideo_CameraRelease(struct uvd *uvd);
+
+static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, unsigned long arg);
+static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
+static int usbvideo_v4l_open(struct inode *inode, struct file *file);
+static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
+                            size_t count, loff_t *ppos);
+static int usbvideo_v4l_close(struct inode *inode, struct file *file);
+
+static int usbvideo_StartDataPump(struct uvd *uvd);
+static void usbvideo_StopDataPump(struct uvd *uvd);
+static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
+static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
+static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
+                                               struct usbvideo_frame *frame);
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+static void *usbvideo_rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void usbvideo_rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+static void RingQueue_Initialize(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       init_waitqueue_head(&rq->wqh);
+}
+
+static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
+{
+       /* Make sure the requested size is a power of 2 and
+          round up if necessary. This allows index wrapping
+          using masks rather than modulo */
+
+       int i = 1;
+       assert(rq != NULL);
+       assert(rqLen > 0);
+
+       while(rqLen >> i)
+               i++;
+       if(rqLen != 1 << (i-1))
+               rqLen = 1 << i;
+
+       rq->length = rqLen;
+       rq->ri = rq->wi = 0;
+       rq->queue = usbvideo_rvmalloc(rq->length);
+       assert(rq->queue != NULL);
+}
+
+static int RingQueue_IsAllocated(const struct RingQueue *rq)
+{
+       if (rq == NULL)
+               return 0;
+       return (rq->queue != NULL) && (rq->length > 0);
+}
+
+static void RingQueue_Free(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       if (RingQueue_IsAllocated(rq)) {
+               usbvideo_rvfree(rq->queue, rq->length);
+               rq->queue = NULL;
+               rq->length = 0;
+       }
+}
+
+int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
+{
+       int rql, toread;
+
+       assert(rq != NULL);
+       assert(dst != NULL);
+
+       rql = RingQueue_GetLength(rq);
+       if(!rql)
+               return 0;
+
+       /* Clip requested length to available data */
+       if(len > rql)
+               len = rql;
+
+       toread = len;
+       if(rq->ri > rq->wi) {
+               /* Read data from tail */
+               int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
+               memcpy(dst, rq->queue + rq->ri, read);
+               toread -= read;
+               dst += read;
+               rq->ri = (rq->ri + read) & (rq->length-1);
+       }
+       if(toread) {
+               /* Read data from head */
+               memcpy(dst, rq->queue + rq->ri, toread);
+               rq->ri = (rq->ri + toread) & (rq->length-1);
+       }
+       return len;
+}
+
+EXPORT_SYMBOL(RingQueue_Dequeue);
+
+int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
+{
+       int enqueued = 0;
+
+       assert(rq != NULL);
+       assert(cdata != NULL);
+       assert(rq->length > 0);
+       while (n > 0) {
+               int m, q_avail;
+
+               /* Calculate the largest chunk that fits the tail of the ring */
+               q_avail = rq->length - rq->wi;
+               if (q_avail <= 0) {
+                       rq->wi = 0;
+                       q_avail = rq->length;
+               }
+               m = n;
+               assert(q_avail > 0);
+               if (m > q_avail)
+                       m = q_avail;
+
+               memcpy(rq->queue + rq->wi, cdata, m);
+               RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
+               cdata += m;
+               enqueued += m;
+               n -= m;
+       }
+       return enqueued;
+}
+
+EXPORT_SYMBOL(RingQueue_Enqueue);
+
+static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       interruptible_sleep_on(&rq->wqh);
+}
+
+void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       if (waitqueue_active(&rq->wqh))
+               wake_up_interruptible(&rq->wqh);
+}
+
+EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
+
+void RingQueue_Flush(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       rq->ri = 0;
+       rq->wi = 0;
+}
+
+EXPORT_SYMBOL(RingQueue_Flush);
+
+
+/*
+ * usbvideo_VideosizeToString()
+ *
+ * This procedure converts given videosize value to readable string.
+ *
+ * History:
+ * 07-Aug-2000 Created.
+ * 19-Oct-2000 Reworked for usbvideo module.
+ */
+static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
+{
+       char tmp[40];
+       int n;
+
+       n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));
+       assert(n < sizeof(tmp));
+       if ((buf == NULL) || (bufLen < n))
+               err("usbvideo_VideosizeToString: buffer is too small.");
+       else
+               memmove(buf, tmp, n);
+}
+
+/*
+ * usbvideo_OverlayChar()
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
+                                int x, int y, int ch)
+{
+       static const unsigned short digits[16] = {
+               0xF6DE, /* 0 */
+               0x2492, /* 1 */
+               0xE7CE, /* 2 */
+               0xE79E, /* 3 */
+               0xB792, /* 4 */
+               0xF39E, /* 5 */
+               0xF3DE, /* 6 */
+               0xF492, /* 7 */
+               0xF7DE, /* 8 */
+               0xF79E, /* 9 */
+               0x77DA, /* a */
+               0xD75C, /* b */
+               0xF24E, /* c */
+               0xD6DC, /* d */
+               0xF34E, /* e */
+               0xF348  /* f */
+       };
+       unsigned short digit;
+       int ix, iy;
+
+       if ((uvd == NULL) || (frame == NULL))
+               return;
+
+       if (ch >= '0' && ch <= '9')
+               ch -= '0';
+       else if (ch >= 'A' && ch <= 'F')
+               ch = 10 + (ch - 'A');
+       else if (ch >= 'a' && ch <= 'f')
+               ch = 10 + (ch - 'a');
+       else
+               return;
+       digit = digits[ch];
+
+       for (iy=0; iy < 5; iy++) {
+               for (ix=0; ix < 3; ix++) {
+                       if (digit & 0x8000) {
+                               if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {
+/* TODO */                             RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
+                               }
+                       }
+                       digit = digit << 1;
+               }
+       }
+}
+
+/*
+ * usbvideo_OverlayString()
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
+                                  int x, int y, const char *str)
+{
+       while (*str) {
+               usbvideo_OverlayChar(uvd, frame, x, y, *str);
+               str++;
+               x += 4; /* 3 pixels character + 1 space */
+       }
+}
+
+/*
+ * usbvideo_OverlayStats()
+ *
+ * Overlays important debugging information.
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       const int y_diff = 8;
+       char tmp[16];
+       int x = 10, y=10;
+       long i, j, barLength;
+       const int qi_x1 = 60, qi_y1 = 10;
+       const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;
+
+       /* Call the user callback, see if we may proceed after that */
+       if (VALID_CALLBACK(uvd, overlayHook)) {
+               if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)
+                       return;
+       }
+
+       /*
+        * We draw a (mostly) hollow rectangle with qi_xxx coordinates.
+        * Left edge symbolizes the queue index 0; right edge symbolizes
+        * the full capacity of the queue.
+        */
+       barLength = qi_x2 - qi_x1 - 2;
+       if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {
+/* TODO */     long u_lo, u_hi, q_used;
+               long m_ri, m_wi, m_lo, m_hi;
+
+               /*
+                * Determine fill zones (used areas of the queue):
+                * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length
+                *
+                * if u_lo < 0 then there is no first filler.
+                */
+
+               q_used = RingQueue_GetLength(&uvd->dp);
+               if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
+                       u_hi = uvd->dp.length;
+                       u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
+               } else {
+                       u_hi = (q_used + uvd->dp.ri);
+                       u_lo = -1;
+               }
+
+               /* Convert byte indices into screen units */
+               m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);
+               m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);
+               m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;
+               m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);
+
+               for (j=qi_y1; j < (qi_y1 + qi_h); j++) {
+                       for (i=qi_x1; i < qi_x2; i++) {
+                               /* Draw border lines */
+                               if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||
+                                   (i == qi_x1) || (i == (qi_x2 - 1))) {
+                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);
+                                       continue;
+                               }
+                               /* For all other points the Y coordinate does not matter */
+                               if ((i >= m_ri) && (i <= (m_ri + 3))) {
+                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);
+                               } else if ((i >= m_wi) && (i <= (m_wi + 3))) {
+                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);
+                               } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))
+                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);
+                       }
+               }
+       }
+
+       sprintf(tmp, "%8lx", uvd->stats.frame_num);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.urb_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.urb_length);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.data_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.header_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.colour);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.hue);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+}
+
+/*
+ * usbvideo_ReportStatistics()
+ *
+ * This procedure prints packet and transfer statistics.
+ *
+ * History:
+ * 14-Jan-2000 Corrected default multiplier.
+ */
+static void usbvideo_ReportStatistics(const struct uvd *uvd)
+{
+       if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
+               unsigned long allPackets, badPackets, goodPackets, percent;
+               allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;
+               badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;
+               goodPackets = allPackets - badPackets;
+               /* Calculate percentage wisely, remember integer limits */
+               assert(allPackets != 0);
+               if (goodPackets < (((unsigned long)-1)/100))
+                       percent = (100 * goodPackets) / allPackets;
+               else
+                       percent = goodPackets / (allPackets / 100);
+               info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",
+                    allPackets, badPackets, percent);
+               if (uvd->iso_packet_len > 0) {
+                       unsigned long allBytes, xferBytes;
+                       char multiplier = ' ';
+                       allBytes = allPackets * uvd->iso_packet_len;
+                       xferBytes = uvd->stats.data_count;
+                       assert(allBytes != 0);
+                       if (xferBytes < (((unsigned long)-1)/100))
+                               percent = (100 * xferBytes) / allBytes;
+                       else
+                               percent = xferBytes / (allBytes / 100);
+                       /* Scale xferBytes for easy reading */
+                       if (xferBytes > 10*1024) {
+                               xferBytes /= 1024;
+                               multiplier = 'K';
+                               if (xferBytes > 10*1024) {
+                                       xferBytes /= 1024;
+                                       multiplier = 'M';
+                                       if (xferBytes > 10*1024) {
+                                               xferBytes /= 1024;
+                                               multiplier = 'G';
+                                               if (xferBytes > 10*1024) {
+                                                       xferBytes /= 1024;
+                                                       multiplier = 'T';
+                                               }
+                                       }
+                               }
+                       }
+                       info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",
+                            xferBytes, multiplier, percent);
+               }
+       }
+}
+
+/*
+ * usbvideo_TestPattern()
+ *
+ * Procedure forms a test pattern (yellow grid on blue background).
+ *
+ * Parameters:
+ * fullframe: if TRUE then entire frame is filled, otherwise the procedure
+ *           continues from the current scanline.
+ * pmode      0: fill the frame with solid blue color (like on VCR or TV)
+ *           1: Draw a colored grid
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
+{
+       struct usbvideo_frame *frame;
+       int num_cell = 0;
+       int scan_length = 0;
+       static int num_pass = 0;
+
+       if (uvd == NULL) {
+               err("%s: uvd == NULL", __FUNCTION__);
+               return;
+       }
+       if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
+               err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
+               return;
+       }
+
+       /* Grab the current frame */
+       frame = &uvd->frame[uvd->curframe];
+
+       /* Optionally start at the beginning */
+       if (fullframe) {
+               frame->curline = 0;
+               frame->seqRead_Length = 0;
+       }
+#if 0
+       {       /* For debugging purposes only */
+               char tmp[20];
+               usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
+               info("testpattern: frame=%s", tmp);
+       }
+#endif
+       /* Form every scan line */
+       for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) {
+               int i;
+               unsigned char *f = frame->data +
+                       (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline);
+               for (i=0; i < VIDEOSIZE_X(frame->request); i++) {
+                       unsigned char cb=0x80;
+                       unsigned char cg = 0;
+                       unsigned char cr = 0;
+
+                       if (pmode == 1) {
+                               if (frame->curline % 32 == 0)
+                                       cb = 0, cg = cr = 0xFF;
+                               else if (i % 32 == 0) {
+                                       if (frame->curline % 32 == 1)
+                                               num_cell++;
+                                       cb = 0, cg = cr = 0xFF;
+                               } else {
+                                       cb = ((num_cell*7) + num_pass) & 0xFF;
+                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
+                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
+                               }
+                       } else {
+                               /* Just the blue screen */
+                       }
+
+                       *f++ = cb;
+                       *f++ = cg;
+                       *f++ = cr;
+                       scan_length += 3;
+               }
+       }
+
+       frame->frameState = FrameState_Done;
+       frame->seqRead_Length += scan_length;
+       ++num_pass;
+
+       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
+       usbvideo_OverlayStats(uvd, frame);
+}
+
+EXPORT_SYMBOL(usbvideo_TestPattern);
+
+
+#ifdef DEBUG
+/*
+ * usbvideo_HexDump()
+ *
+ * A debugging tool. Prints hex dumps.
+ *
+ * History:
+ * 29-Jul-2000 Added printing of offsets.
+ */
+void usbvideo_HexDump(const unsigned char *data, int len)
+{
+       const int bytes_per_line = 32;
+       char tmp[128]; /* 32*3 + 5 */
+       int i, k;
+
+       for (i=k=0; len > 0; i++, len--) {
+               if (i > 0 && ((i % bytes_per_line) == 0)) {
+                       printk("%s\n", tmp);
+                       k=0;
+               }
+               if ((i % bytes_per_line) == 0)
+                       k += sprintf(&tmp[k], "%04x: ", i);
+               k += sprintf(&tmp[k], "%02x ", data[i]);
+       }
+       if (k > 0)
+               printk("%s\n", tmp);
+}
+
+EXPORT_SYMBOL(usbvideo_HexDump);
+
+#endif
+
+/* ******************************************************************** */
+
+/* XXX: this piece of crap really wants some error handling.. */
+static void usbvideo_ClientIncModCount(struct uvd *uvd)
+{
+       if (uvd == NULL) {
+               err("%s: uvd == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle == NULL) {
+               err("%s: uvd->handle == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle->md_module == NULL) {
+               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+               return;
+       }
+       if (!try_module_get(uvd->handle->md_module)) {
+               err("%s: try_module_get() == 0", __FUNCTION__);
+               return;
+       }
+}
+
+static void usbvideo_ClientDecModCount(struct uvd *uvd)
+{
+       if (uvd == NULL) {
+               err("%s: uvd == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle == NULL) {
+               err("%s: uvd->handle == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle->md_module == NULL) {
+               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+               return;
+       }
+       module_put(uvd->handle->md_module);
+}
+
+int usbvideo_register(
+       struct usbvideo **pCams,
+       const int num_cams,
+       const int num_extra,
+       const char *driverName,
+       const struct usbvideo_cb *cbTbl,
+       struct module *md,
+       const struct usb_device_id *id_table)
+{
+       struct usbvideo *cams;
+       int i, base_size, result;
+
+       /* Check parameters for sanity */
+       if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
+               err("%s: Illegal call", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       /* Check registration callback - must be set! */
+       if (cbTbl->probe == NULL) {
+               err("%s: probe() is required!", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
+       cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
+       if (cams == NULL) {
+               err("Failed to allocate %d. bytes for usbvideo struct", base_size);
+               return -ENOMEM;
+       }
+       dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
+           __FUNCTION__, cams, base_size, num_cams);
+
+       /* Copy callbacks, apply defaults for those that are not set */
+       memmove(&cams->cb, cbTbl, sizeof(cams->cb));
+       if (cams->cb.getFrame == NULL)
+               cams->cb.getFrame = usbvideo_GetFrame;
+       if (cams->cb.disconnect == NULL)
+               cams->cb.disconnect = usbvideo_Disconnect;
+       if (cams->cb.startDataPump == NULL)
+               cams->cb.startDataPump = usbvideo_StartDataPump;
+       if (cams->cb.stopDataPump == NULL)
+               cams->cb.stopDataPump = usbvideo_StopDataPump;
+
+       cams->num_cameras = num_cams;
+       cams->cam = (struct uvd *) &cams[1];
+       cams->md_module = md;
+       if (cams->md_module == NULL)
+               warn("%s: module == NULL!", __FUNCTION__);
+       mutex_init(&cams->lock);        /* to 1 == available */
+
+       for (i = 0; i < num_cams; i++) {
+               struct uvd *up = &cams->cam[i];
+
+               up->handle = cams;
+
+               /* Allocate user_data separately because of kmalloc's limits */
+               if (num_extra > 0) {
+                       up->user_size = num_cams * num_extra;
+                       up->user_data = kmalloc(up->user_size, GFP_KERNEL);
+                       if (up->user_data == NULL) {
+                               err("%s: Failed to allocate user_data (%d. bytes)",
+                                   __FUNCTION__, up->user_size);
+                               while (i) {
+                                       up = &cams->cam[--i];
+                                       kfree(up->user_data);
+                               }
+                               kfree(cams);
+                               return -ENOMEM;
+                       }
+                       dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
+                            __FUNCTION__, i, up->user_data, up->user_size);
+               }
+       }
+
+       /*
+        * Register ourselves with USB stack.
+        */
+       strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown");
+       cams->usbdrv.name = cams->drvName;
+       cams->usbdrv.probe = cams->cb.probe;
+       cams->usbdrv.disconnect = cams->cb.disconnect;
+       cams->usbdrv.id_table = id_table;
+
+       /*
+        * Update global handle to usbvideo. This is very important
+        * because probe() can be called before usb_register() returns.
+        * If the handle is not yet updated then the probe() will fail.
+        */
+       *pCams = cams;
+       result = usb_register(&cams->usbdrv);
+       if (result) {
+               for (i = 0; i < num_cams; i++) {
+                       struct uvd *up = &cams->cam[i];
+                       kfree(up->user_data);
+               }
+               kfree(cams);
+       }
+
+       return result;
+}
+
+EXPORT_SYMBOL(usbvideo_register);
+
+/*
+ * usbvideo_Deregister()
+ *
+ * Procedure frees all usbvideo and user data structures. Be warned that
+ * if you had some dynamically allocated components in ->user field then
+ * you should free them before calling here.
+ */
+void usbvideo_Deregister(struct usbvideo **pCams)
+{
+       struct usbvideo *cams;
+       int i;
+
+       if (pCams == NULL) {
+               err("%s: pCams == NULL", __FUNCTION__);
+               return;
+       }
+       cams = *pCams;
+       if (cams == NULL) {
+               err("%s: cams == NULL", __FUNCTION__);
+               return;
+       }
+
+       dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
+       usb_deregister(&cams->usbdrv);
+
+       dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
+       for (i=0; i < cams->num_cameras; i++) {
+               struct uvd *up = &cams->cam[i];
+               int warning = 0;
+
+               if (up->user_data != NULL) {
+                       if (up->user_size <= 0)
+                               ++warning;
+               } else {
+                       if (up->user_size > 0)
+                               ++warning;
+               }
+               if (warning) {
+                       err("%s: Warning: user_data=$%p user_size=%d.",
+                           __FUNCTION__, up->user_data, up->user_size);
+               } else {
+                       dbg("%s: Freeing %d. $%p->user_data=$%p",
+                           __FUNCTION__, i, up, up->user_data);
+                       kfree(up->user_data);
+               }
+       }
+       /* Whole array was allocated in one chunk */
+       dbg("%s: Freed %d uvd structures",
+           __FUNCTION__, cams->num_cameras);
+       kfree(cams);
+       *pCams = NULL;
+}
+
+EXPORT_SYMBOL(usbvideo_Deregister);
+
+/*
+ * usbvideo_Disconnect()
+ *
+ * This procedure stops all driver activity. Deallocation of
+ * the interface-private structure (pointed by 'ptr') is done now
+ * (if we don't have any open files) or later, when those files
+ * are closed. After that driver should be removable.
+ *
+ * This code handles surprise removal. The uvd->user is a counter which
+ * increments on open() and decrements on close(). If we see here that
+ * this counter is not 0 then we have a client who still has us opened.
+ * We set uvd->remove_pending flag as early as possible, and after that
+ * all access to the camera will gracefully fail. These failures should
+ * prompt client to (eventually) close the video device, and then - in
+ * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter.
+ *
+ * History:
+ * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone.
+ * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close()
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ * 19-Oct-2000 Moved to usbvideo module.
+ */
+static void usbvideo_Disconnect(struct usb_interface *intf)
+{
+       struct uvd *uvd = usb_get_intfdata (intf);
+       int i;
+
+       if (uvd == NULL) {
+               err("%s($%p): Illegal call.", __FUNCTION__, intf);
+               return;
+       }
+
+       usb_set_intfdata (intf, NULL);
+
+       usbvideo_ClientIncModCount(uvd);
+       if (uvd->debug > 0)
+               info("%s(%p.)", __FUNCTION__, intf);
+
+       mutex_lock(&uvd->lock);
+       uvd->remove_pending = 1; /* Now all ISO data will be ignored */
+
+       /* At this time we ask to cancel outstanding URBs */
+       GET_CALLBACK(uvd, stopDataPump)(uvd);
+
+       for (i=0; i < USBVIDEO_NUMSBUF; i++)
+               usb_free_urb(uvd->sbuf[i].urb);
+
+       usb_put_dev(uvd->dev);
+       uvd->dev = NULL;            /* USB device is no more */
+
+       video_unregister_device(&uvd->vdev);
+       if (uvd->debug > 0)
+               info("%s: Video unregistered.", __FUNCTION__);
+
+       if (uvd->user)
+               info("%s: In use, disconnect pending.", __FUNCTION__);
+       else
+               usbvideo_CameraRelease(uvd);
+       mutex_unlock(&uvd->lock);
+       info("USB camera disconnected.");
+
+       usbvideo_ClientDecModCount(uvd);
+}
+
+/*
+ * usbvideo_CameraRelease()
+ *
+ * This code does final release of uvd. This happens
+ * after the device is disconnected -and- all clients
+ * closed their files.
+ *
+ * History:
+ * 27-Jan-2000 Created.
+ */
+static void usbvideo_CameraRelease(struct uvd *uvd)
+{
+       if (uvd == NULL) {
+               err("%s: Illegal call", __FUNCTION__);
+               return;
+       }
+
+       RingQueue_Free(&uvd->dp);
+       if (VALID_CALLBACK(uvd, userFree))
+               GET_CALLBACK(uvd, userFree)(uvd);
+       uvd->uvd_used = 0;      /* This is atomic, no need to take mutex */
+}
+
+/*
+ * usbvideo_find_struct()
+ *
+ * This code searches the array of preallocated (static) structures
+ * and returns index of the first one that isn't in use. Returns -1
+ * if there are no free structures.
+ *
+ * History:
+ * 27-Jan-2000 Created.
+ */
+static int usbvideo_find_struct(struct usbvideo *cams)
+{
+       int u, rv = -1;
+
+       if (cams == NULL) {
+               err("No usbvideo handle?");
+               return -1;
+       }
+       mutex_lock(&cams->lock);
+       for (u = 0; u < cams->num_cameras; u++) {
+               struct uvd *uvd = &cams->cam[u];
+               if (!uvd->uvd_used) /* This one is free */
+               {
+                       uvd->uvd_used = 1;      /* In use now */
+                       mutex_init(&uvd->lock); /* to 1 == available */
+                       uvd->dev = NULL;
+                       rv = u;
+                       break;
+               }
+       }
+       mutex_unlock(&cams->lock);
+       return rv;
+}
+
+static struct file_operations usbvideo_fops = {
+       .owner =  THIS_MODULE,
+       .open =   usbvideo_v4l_open,
+       .release =usbvideo_v4l_close,
+       .read =   usbvideo_v4l_read,
+       .mmap =   usbvideo_v4l_mmap,
+       .ioctl =  usbvideo_v4l_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek = no_llseek,
+};
+static const struct video_device usbvideo_template = {
+       .owner =      THIS_MODULE,
+       .type =       VID_TYPE_CAPTURE,
+       .hardware =   VID_HARDWARE_CPIA,
+       .fops =       &usbvideo_fops,
+};
+
+struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
+{
+       int i, devnum;
+       struct uvd *uvd = NULL;
+
+       if (cams == NULL) {
+               err("No usbvideo handle?");
+               return NULL;
+       }
+
+       devnum = usbvideo_find_struct(cams);
+       if (devnum == -1) {
+               err("IBM USB camera driver: Too many devices!");
+               return NULL;
+       }
+       uvd = &cams->cam[devnum];
+       dbg("Device entry #%d. at $%p", devnum, uvd);
+
+       /* Not relying upon caller we increase module counter ourselves */
+       usbvideo_ClientIncModCount(uvd);
+
+       mutex_lock(&uvd->lock);
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+               if (uvd->sbuf[i].urb == NULL) {
+                       err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC);
+                       uvd->uvd_used = 0;
+                       uvd = NULL;
+                       goto allocate_done;
+               }
+       }
+       uvd->user=0;
+       uvd->remove_pending = 0;
+       uvd->last_error = 0;
+       RingQueue_Initialize(&uvd->dp);
+
+       /* Initialize video device structure */
+       uvd->vdev = usbvideo_template;
+       sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
+       /*
+        * The client is free to overwrite those because we
+        * return control to the client's probe function right now.
+        */
+allocate_done:
+       mutex_unlock(&uvd->lock);
+       usbvideo_ClientDecModCount(uvd);
+       return uvd;
+}
+
+EXPORT_SYMBOL(usbvideo_AllocateDevice);
+
+int usbvideo_RegisterVideoDevice(struct uvd *uvd)
+{
+       char tmp1[20], tmp2[20];        /* Buffers for printing */
+
+       if (uvd == NULL) {
+               err("%s: Illegal call.", __FUNCTION__);
+               return -EINVAL;
+       }
+       if (uvd->video_endp == 0) {
+               info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
+       }
+       if (uvd->paletteBits == 0) {
+               err("%s: No palettes specified!", __FUNCTION__);
+               return -EINVAL;
+       }
+       if (uvd->defaultPalette == 0) {
+               info("%s: No default palette!", __FUNCTION__);
+       }
+
+       uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
+               VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL;
+       usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize);
+       usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
+
+       if (uvd->debug > 0) {
+               info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
+                    __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+       }
+       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               err("%s: video_register_device failed", __FUNCTION__);
+               return -EPIPE;
+       }
+       if (uvd->debug > 1) {
+               info("%s: video_register_device() successful", __FUNCTION__);
+       }
+       if (uvd->dev == NULL) {
+               err("%s: uvd->dev == NULL", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       info("%s on /dev/video%d: canvas=%s videosize=%s",
+            (uvd->handle != NULL) ? uvd->handle->drvName : "???",
+            uvd->vdev.minor, tmp2, tmp1);
+
+       usb_get_dev(uvd->dev);
+       return 0;
+}
+
+EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
+
+/* ******************************************************************** */
+
+static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct uvd *uvd = file->private_data;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return -EFAULT;
+
+       if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+               return -EINVAL;
+
+       pos = (unsigned long) uvd->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+/*
+ * usbvideo_v4l_open()
+ *
+ * This is part of Video 4 Linux API. The driver can be opened by one
+ * client only (checks internal counter 'uvdser'). The procedure
+ * then allocates buffers needed for video processing.
+ *
+ * History:
+ * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the
+ *             camera is also initialized here (once per connect), at
+ *             expense of V4L client (it waits on open() call).
+ * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ */
+static int usbvideo_v4l_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct uvd *uvd = (struct uvd *) dev;
+       const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
+       int i, errCode = 0;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, dev);
+
+       usbvideo_ClientIncModCount(uvd);
+       mutex_lock(&uvd->lock);
+
+       if (uvd->user) {
+               err("%s: Someone tried to open an already opened device!", __FUNCTION__);
+               errCode = -EBUSY;
+       } else {
+               /* Clear statistics */
+               memset(&uvd->stats, 0, sizeof(uvd->stats));
+
+               /* Clean pointers so we know if we allocated something */
+               for (i=0; i < USBVIDEO_NUMSBUF; i++)
+                       uvd->sbuf[i].data = NULL;
+
+               /* Allocate memory for the frame buffers */
+               uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
+               uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
+               RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
+               if ((uvd->fbuf == NULL) ||
+                   (!RingQueue_IsAllocated(&uvd->dp))) {
+                       err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
+                       errCode = -ENOMEM;
+               } else {
+                       /* Allocate all buffers */
+                       for (i=0; i < USBVIDEO_NUMFRAMES; i++) {
+                               uvd->frame[i].frameState = FrameState_Unused;
+                               uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);
+                               /*
+                                * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
+                                * is not used (using read() instead).
+                                */
+                               uvd->frame[i].canvas = uvd->canvas;
+                               uvd->frame[i].seqRead_Index = 0;
+                       }
+                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+                               uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
+                               if (uvd->sbuf[i].data == NULL) {
+                                       errCode = -ENOMEM;
+                                       break;
+                               }
+                       }
+               }
+               if (errCode != 0) {
+                       /* Have to free all that memory */
+                       if (uvd->fbuf != NULL) {
+                               usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
+                               uvd->fbuf = NULL;
+                       }
+                       RingQueue_Free(&uvd->dp);
+                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+                               kfree(uvd->sbuf[i].data);
+                               uvd->sbuf[i].data = NULL;
+                       }
+               }
+       }
+
+       /* If so far no errors then we shall start the camera */
+       if (errCode == 0) {
+               /* Start data pump if we have valid endpoint */
+               if (uvd->video_endp != 0)
+                       errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
+               if (errCode == 0) {
+                       if (VALID_CALLBACK(uvd, setupOnOpen)) {
+                               if (uvd->debug > 1)
+                                       info("%s: setupOnOpen callback", __FUNCTION__);
+                               errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
+                               if (errCode < 0) {
+                                       err("%s: setupOnOpen callback failed (%d.).",
+                                           __FUNCTION__, errCode);
+                               } else if (uvd->debug > 1) {
+                                       info("%s: setupOnOpen callback successful", __FUNCTION__);
+                               }
+                       }
+                       if (errCode == 0) {
+                               uvd->settingsAdjusted = 0;
+                               if (uvd->debug > 1)
+                                       info("%s: Open succeeded.", __FUNCTION__);
+                               uvd->user++;
+                               file->private_data = uvd;
+                       }
+               }
+       }
+       mutex_unlock(&uvd->lock);
+       if (errCode != 0)
+               usbvideo_ClientDecModCount(uvd);
+       if (uvd->debug > 0)
+               info("%s: Returning %d.", __FUNCTION__, errCode);
+       return errCode;
+}
+
+/*
+ * usbvideo_v4l_close()
+ *
+ * This is part of Video 4 Linux API. The procedure
+ * stops streaming and deallocates all buffers that were earlier
+ * allocated in usbvideo_v4l_open().
+ *
+ * History:
+ * 22-Jan-2000 Moved scratch buffer deallocation here.
+ * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
+ * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
+ */
+static int usbvideo_v4l_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = file->private_data;
+       struct uvd *uvd = (struct uvd *) dev;
+       int i;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, dev);
+
+       mutex_lock(&uvd->lock);
+       GET_CALLBACK(uvd, stopDataPump)(uvd);
+       usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
+       uvd->fbuf = NULL;
+       RingQueue_Free(&uvd->dp);
+
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               kfree(uvd->sbuf[i].data);
+               uvd->sbuf[i].data = NULL;
+       }
+
+#if USBVIDEO_REPORT_STATS
+       usbvideo_ReportStatistics(uvd);
+#endif
+
+       uvd->user--;
+       if (uvd->remove_pending) {
+               if (uvd->debug > 0)
+                       info("usbvideo_v4l_close: Final disconnect.");
+               usbvideo_CameraRelease(uvd);
+       }
+       mutex_unlock(&uvd->lock);
+       usbvideo_ClientDecModCount(uvd);
+
+       if (uvd->debug > 1)
+               info("%s: Completed.", __FUNCTION__);
+       file->private_data = NULL;
+       return 0;
+}
+
+/*
+ * usbvideo_v4l_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ * History:
+ * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
+ */
+static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
+                                unsigned int cmd, void *arg)
+{
+       struct uvd *uvd = file->private_data;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return -EIO;
+
+       switch (cmd) {
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *b = arg;
+                       *b = uvd->vcap;
+                       return 0;
+               }
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+                       *v = uvd->vchan;
+                       return 0;
+               }
+               case VIDIOCSCHAN:
+               {
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *pic = arg;
+                       *pic = uvd->vpic;
+                       return 0;
+               }
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *pic = arg;
+                       /*
+                        * Use temporary 'video_picture' structure to preserve our
+                        * own settings (such as color depth, palette) that we
+                        * aren't allowing everyone (V4L client) to change.
+                        */
+                       uvd->vpic.brightness = pic->brightness;
+                       uvd->vpic.hue = pic->hue;
+                       uvd->vpic.colour = pic->colour;
+                       uvd->vpic.contrast = pic->contrast;
+                       uvd->settingsAdjusted = 0;      /* Will force new settings */
+                       return 0;
+               }
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       if(VALID_CALLBACK(uvd, setVideoMode)) {
+                               return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
+                       }
+
+                       if (vw->flags)
+                               return -EINVAL;
+                       if (vw->clipcount)
+                               return -EINVAL;
+                       if (vw->width != VIDEOSIZE_X(uvd->canvas))
+                               return -EINVAL;
+                       if (vw->height != VIDEOSIZE_Y(uvd->canvas))
+                               return -EINVAL;
+
+                       return 0;
+               }
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = VIDEOSIZE_X(uvd->videosize);
+                       vw->height = VIDEOSIZE_Y(uvd->videosize);
+                       vw->chromakey = 0;
+                       if (VALID_CALLBACK(uvd, getFPS))
+                               vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
+                       else
+                               vw->flags = 10; /* FIXME: do better! */
+                       return 0;
+               }
+               case VIDIOCGMBUF:
+               {
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset(vm, 0, sizeof(*vm));
+                       vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
+                       vm->frames = USBVIDEO_NUMFRAMES;
+                       for(i = 0; i < USBVIDEO_NUMFRAMES; i++)
+                         vm->offsets[i] = i * uvd->max_frame_size;
+
+                       return 0;
+               }
+               case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap *vm = arg;
+
+                       if (uvd->debug >= 1) {
+                               info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
+                                    vm->frame, vm->width, vm->height, vm->format);
+                       }
+                       /*
+                        * Check if the requested size is supported. If the requestor
+                        * requests too big a frame then we may be tricked into accessing
+                        * outside of own preallocated frame buffer (in uvd->frame).
+                        * This will cause oops or a security hole. Theoretically, we
+                        * could only clamp the size down to acceptable bounds, but then
+                        * we'd need to figure out how to insert our smaller buffer into
+                        * larger caller's buffer... this is not an easy question. So we
+                        * here just flatly reject too large requests, assuming that the
+                        * caller will resubmit with smaller size. Callers should know
+                        * what size we support (returned by VIDIOCGCAP). However vidcat,
+                        * for one, does not care and allows to ask for any size.
+                        */
+                       if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
+                           (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
+                               if (uvd->debug > 0) {
+                                       info("VIDIOCMCAPTURE: Size=%dx%d too large; "
+                                            "allowed only up to %ldx%ld", vm->width, vm->height,
+                                            VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
+                               }
+                               return -EINVAL;
+                       }
+                       /* Check if the palette is supported */
+                       if (((1L << vm->format) & uvd->paletteBits) == 0) {
+                               if (uvd->debug > 0) {
+                                       info("VIDIOCMCAPTURE: format=%d. not supported"
+                                            " (paletteBits=$%08lx)",
+                                            vm->format, uvd->paletteBits);
+                               }
+                               return -EINVAL;
+                       }
+                       if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
+                               err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
+                               return -EINVAL;
+                       }
+                       if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
+                               /* Not an error - can happen */
+                       }
+                       uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
+                       uvd->frame[vm->frame].palette = vm->format;
+
+                       /* Mark it as ready */
+                       uvd->frame[vm->frame].frameState = FrameState_Ready;
+
+                       return usbvideo_NewFrame(uvd, vm->frame);
+               }
+               case VIDIOCSYNC:
+               {
+                       int *frameNum = arg;
+                       int ret;
+
+                       if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
+                               return -EINVAL;
+
+                       if (uvd->debug >= 1)
+                               info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
+                       if (uvd->flags & FLAGS_NO_DECODING)
+                               ret = usbvideo_GetFrame(uvd, *frameNum);
+                       else if (VALID_CALLBACK(uvd, getFrame)) {
+                               ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
+                               if ((ret < 0) && (uvd->debug >= 1)) {
+                                       err("VIDIOCSYNC: getFrame() returned %d.", ret);
+                               }
+                       } else {
+                               err("VIDIOCSYNC: getFrame is not set");
+                               ret = -EFAULT;
+                       }
+
+                       /*
+                        * The frame is in FrameState_Done_Hold state. Release it
+                        * right now because its data is already mapped into
+                        * the user space and it's up to the application to
+                        * make use of it until it asks for another frame.
+                        */
+                       uvd->frame[*frameNum].frameState = FrameState_Unused;
+                       return ret;
+               }
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb, 0, sizeof(*vb));
+                       return 0;
+               }
+               case VIDIOCKEY:
+                       return 0;
+
+               case VIDIOCCAPTURE:
+                       return -EINVAL;
+
+               case VIDIOCSFBUF:
+
+               case VIDIOCGTUNER:
+               case VIDIOCSTUNER:
+
+               case VIDIOCGFREQ:
+               case VIDIOCSFREQ:
+
+               case VIDIOCGAUDIO:
+               case VIDIOCSAUDIO:
+                       return -EINVAL;
+
+               default:
+                       return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
+}
+
+/*
+ * usbvideo_v4l_read()
+ *
+ * This is mostly boring stuff. We simply ask for a frame and when it
+ * arrives copy all the video data from it into user space. There is
+ * no obvious need to override this method.
+ *
+ * History:
+ * 20-Oct-2000 Created.
+ * 01-Nov-2000 Added mutex (uvd->lock).
+ */
+static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
+                     size_t count, loff_t *ppos)
+{
+       struct uvd *uvd = file->private_data;
+       int noblock = file->f_flags & O_NONBLOCK;
+       int frmx = -1, i;
+       struct usbvideo_frame *frame;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
+               return -EFAULT;
+
+       if (uvd->debug >= 1)
+               info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
+
+       mutex_lock(&uvd->lock);
+
+       /* See if a frame is completed, then use it. */
+       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+               if ((uvd->frame[i].frameState == FrameState_Done) ||
+                   (uvd->frame[i].frameState == FrameState_Done_Hold) ||
+                   (uvd->frame[i].frameState == FrameState_Error)) {
+                       frmx = i;
+                       break;
+               }
+       }
+
+       /* FIXME: If we don't start a frame here then who ever does? */
+       if (noblock && (frmx == -1)) {
+               count = -EAGAIN;
+               goto read_done;
+       }
+
+       /*
+        * If no FrameState_Done, look for a FrameState_Grabbing state.
+        * See if a frame is in process (grabbing), then use it.
+        * We will need to wait until it becomes cooked, of course.
+        */
+       if (frmx == -1) {
+               for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+                       if (uvd->frame[i].frameState == FrameState_Grabbing) {
+                               frmx = i;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If no frame is active, start one. We don't care which one
+        * it will be, so #0 is as good as any.
+        * In read access mode we don't have convenience of VIDIOCMCAPTURE
+        * to specify the requested palette (video format) on per-frame
+        * basis. This means that we have to return data in -some- format
+        * and just hope that the client knows what to do with it.
+        * The default format is configured in uvd->defaultPalette field
+        * as one of VIDEO_PALETTE_xxx values. We stuff it into the new
+        * frame and initiate the frame filling process.
+        */
+       if (frmx == -1) {
+               if (uvd->defaultPalette == 0) {
+                       err("%s: No default palette; don't know what to do!", __FUNCTION__);
+                       count = -EFAULT;
+                       goto read_done;
+               }
+               frmx = 0;
+               /*
+                * We have no per-frame control over video size.
+                * Therefore we only can use whatever size was
+                * specified as default.
+                */
+               uvd->frame[frmx].request = uvd->videosize;
+               uvd->frame[frmx].palette = uvd->defaultPalette;
+               uvd->frame[frmx].frameState = FrameState_Ready;
+               usbvideo_NewFrame(uvd, frmx);
+               /* Now frame 0 is supposed to start filling... */
+       }
+
+       /*
+        * Get a pointer to the active frame. It is either previously
+        * completed frame or frame in progress but not completed yet.
+        */
+       frame = &uvd->frame[frmx];
+
+       /*
+        * Sit back & wait until the frame gets filled and postprocessed.
+        * If we fail to get the picture [in time] then return the error.
+        * In this call we specify that we want the frame to be waited for,
+        * postprocessed and switched into FrameState_Done_Hold state. This
+        * state is used to hold the frame as "fully completed" between
+        * subsequent partial reads of the same frame.
+        */
+       if (frame->frameState != FrameState_Done_Hold) {
+               long rv = -EFAULT;
+               if (uvd->flags & FLAGS_NO_DECODING)
+                       rv = usbvideo_GetFrame(uvd, frmx);
+               else if (VALID_CALLBACK(uvd, getFrame))
+                       rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);
+               else
+                       err("getFrame is not set");
+               if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {
+                       count = rv;
+                       goto read_done;
+               }
+       }
+
+       /*
+        * Copy bytes to user space. We allow for partial reads, which
+        * means that the user application can request read less than
+        * the full frame size. It is up to the application to issue
+        * subsequent calls until entire frame is read.
+        *
+        * First things first, make sure we don't copy more than we
+        * have - even if the application wants more. That would be
+        * a big security embarassment!
+        */
+       if ((count + frame->seqRead_Index) > frame->seqRead_Length)
+               count = frame->seqRead_Length - frame->seqRead_Index;
+
+       /*
+        * Copy requested amount of data to user space. We start
+        * copying from the position where we last left it, which
+        * will be zero for a new frame (not read before).
+        */
+       if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {
+               count = -EFAULT;
+               goto read_done;
+       }
+
+       /* Update last read position */
+       frame->seqRead_Index += count;
+       if (uvd->debug >= 1) {
+               err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
+                       __FUNCTION__, count, frame->seqRead_Index);
+       }
+
+       /* Finally check if the frame is done with and "release" it */
+       if (frame->seqRead_Index >= frame->seqRead_Length) {
+               /* All data has been read */
+               frame->seqRead_Index = 0;
+
+               /* Mark it as available to be used again. */
+               uvd->frame[frmx].frameState = FrameState_Unused;
+               if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
+                       err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
+               }
+       }
+read_done:
+       mutex_unlock(&uvd->lock);
+       return count;
+}
+
+/*
+ * Make all of the blocks of data contiguous
+ */
+static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
+{
+       char *cdata;
+       int i, totlen = 0;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               int n = urb->iso_frame_desc[i].actual_length;
+               int st = urb->iso_frame_desc[i].status;
+
+               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               /* Detect and ignore errored packets */
+               if (st < 0) {
+                       if (uvd->debug >= 1)
+                               err("Data error: packet=%d. len=%d. status=%d.", i, n, st);
+                       uvd->stats.iso_err_count++;
+                       continue;
+               }
+
+               /* Detect and ignore empty packets */
+               if (n <= 0) {
+                       uvd->stats.iso_skip_count++;
+                       continue;
+               }
+               totlen += n;    /* Little local accounting */
+               RingQueue_Enqueue(&uvd->dp, cdata, n);
+       }
+       return totlen;
+}
+
+static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs)
+{
+       int i, ret, len;
+       struct uvd *uvd = urb->context;
+
+       /* We don't want to do anything if we are about to be removed! */
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return;
+#if 0
+       if (urb->actual_length > 0) {
+               info("urb=$%p status=%d. errcount=%d. length=%d.",
+                    urb, urb->status, urb->error_count, urb->actual_length);
+       } else {
+               static int c = 0;
+               if (c++ % 100 == 0)
+                       info("No Isoc data");
+       }
+#endif
+
+       if (!uvd->streaming) {
+               if (uvd->debug >= 1)
+                       info("Not streaming, but interrupt!");
+               return;
+       }
+
+       uvd->stats.urb_count++;
+       if (urb->actual_length <= 0)
+               goto urb_done_with;
+
+       /* Copy the data received into ring queue */
+       len = usbvideo_CompressIsochronous(uvd, urb);
+       uvd->stats.urb_length = len;
+       if (len <= 0)
+               goto urb_done_with;
+
+       /* Here we got some data */
+       uvd->stats.data_count += len;
+       RingQueue_WakeUpInterruptible(&uvd->dp);
+
+urb_done_with:
+       for (i = 0; i < FRAMES_PER_DESC; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+       urb->status = 0;
+       urb->dev = uvd->dev;
+       ret = usb_submit_urb (urb, GFP_KERNEL);
+       if(ret)
+               err("usb_submit_urb error (%d)", ret);
+       return;
+}
+
+/*
+ * usbvideo_StartDataPump()
+ *
+ * History:
+ * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead
+ *             of hardcoded values. Simplified by using for loop,
+ *             allowed any number of URBs.
+ */
+static int usbvideo_StartDataPump(struct uvd *uvd)
+{
+       struct usb_device *dev = uvd->dev;
+       int i, errFlag;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, uvd);
+
+       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+               err("%s: Camera is not operational", __FUNCTION__);
+               return -EFAULT;
+       }
+       uvd->curframe = -1;
+
+       /* Alternate interface 1 is is the biggest frame size */
+       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
+       if (i < 0) {
+               err("%s: usb_set_interface error", __FUNCTION__);
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+       if (VALID_CALLBACK(uvd, videoStart))
+               GET_CALLBACK(uvd, videoStart)(uvd);
+       else
+               err("%s: videoStart not set", __FUNCTION__);
+
+       /* We double buffer the Iso lists */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               int j, k;
+               struct urb *urb = uvd->sbuf[i].urb;
+               urb->dev = dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = uvd->sbuf[i].data;
+               urb->complete = usbvideo_IsocIrq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
+               for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = uvd->iso_packet_len;
+               }
+       }
+
+       /* Submit all URBs */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+               if (errFlag)
+                       err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
+       }
+
+       uvd->streaming = 1;
+       if (uvd->debug > 1)
+               info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
+       return 0;
+}
+
+/*
+ * usbvideo_StopDataPump()
+ *
+ * This procedure stops streaming and deallocates URBs. Then it
+ * activates zero-bandwidth alt. setting of the video interface.
+ *
+ * History:
+ * 22-Jan-2000 Corrected order of actions to work after surprise removal.
+ * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
+ */
+static void usbvideo_StopDataPump(struct uvd *uvd)
+{
+       int i, j;
+
+       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+               return;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, uvd);
+
+       /* Unschedule all of the iso td's */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               usb_kill_urb(uvd->sbuf[i].urb);
+       }
+       if (uvd->debug > 1)
+               info("%s: streaming=0", __FUNCTION__);
+       uvd->streaming = 0;
+
+       if (!uvd->remove_pending) {
+               /* Invoke minidriver's magic to stop the camera */
+               if (VALID_CALLBACK(uvd, videoStop))
+                       GET_CALLBACK(uvd, videoStop)(uvd);
+               else
+                       err("%s: videoStop not set", __FUNCTION__);
+
+               /* Set packet size to 0 */
+               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
+               if (j < 0) {
+                       err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
+                       uvd->last_error = j;
+               }
+       }
+}
+
+/*
+ * usbvideo_NewFrame()
+ *
+ * History:
+ * 29-Mar-00 Added copying of previous frame into the current one.
+ * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
+ */
+static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
+{
+       struct usbvideo_frame *frame;
+       int n;
+
+       if (uvd->debug > 1)
+               info("usbvideo_NewFrame($%p,%d.)", uvd, framenum);
+
+       /* If we're not grabbing a frame right now and the other frame is */
+       /*  ready to be grabbed into, then use it instead */
+       if (uvd->curframe != -1)
+               return 0;
+
+       /* If necessary we adjust picture settings between frames */
+       if (!uvd->settingsAdjusted) {
+               if (VALID_CALLBACK(uvd, adjustPicture))
+                       GET_CALLBACK(uvd, adjustPicture)(uvd);
+               uvd->settingsAdjusted = 1;
+       }
+
+       n = (framenum + 1) % USBVIDEO_NUMFRAMES;
+       if (uvd->frame[n].frameState == FrameState_Ready)
+               framenum = n;
+
+       frame = &uvd->frame[framenum];
+
+       frame->frameState = FrameState_Grabbing;
+       frame->scanstate = ScanState_Scanning;
+       frame->seqRead_Length = 0;      /* Accumulated in xxx_parse_data() */
+       frame->deinterlace = Deinterlace_None;
+       frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */
+       uvd->curframe = framenum;
+
+       /*
+        * Normally we would want to copy previous frame into the current one
+        * before we even start filling it with data; this allows us to stop
+        * filling at any moment; top portion of the frame will be new and
+        * bottom portion will stay as it was in previous frame. If we don't
+        * do that then missing chunks of video stream will result in flickering
+        * portions of old data whatever it was before.
+        *
+        * If we choose not to copy previous frame (to, for example, save few
+        * bus cycles - the frame can be pretty large!) then we have an option
+        * to clear the frame before using. If we experience losses in this
+        * mode then missing picture will be black (no flickering).
+        *
+        * Finally, if user chooses not to clean the current frame before
+        * filling it with data then the old data will be visible if we fail
+        * to refill entire frame with new data.
+        */
+       if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
+               /* This copies previous frame into this one to mask losses */
+               int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
+               memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
+       } else {
+               if (uvd->flags & FLAGS_CLEAN_FRAMES) {
+                       /* This provides a "clean" frame but slows things down */
+                       memset(frame->data, 0, uvd->max_frame_size);
+               }
+       }
+       return 0;
+}
+
+/*
+ * usbvideo_CollectRawData()
+ *
+ * This procedure can be used instead of 'processData' callback if you
+ * only want to dump the raw data from the camera into the output
+ * device (frame buffer). You can look at it with V4L client, but the
+ * image will be unwatchable. The main purpose of this code and of the
+ * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from
+ * new, unknown cameras. This procedure will be automatically invoked
+ * instead of the specified callback handler when uvd->flags has bit
+ * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
+ * based on usbvideo can use this feature at any time.
+ */
+static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       int n;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+
+       /* Try to move data from queue into frame buffer */
+       n = RingQueue_GetLength(&uvd->dp);
+       if (n > 0) {
+               int m;
+               /* See how much space we have left */
+               m = uvd->max_frame_size - frame->seqRead_Length;
+               if (n > m)
+                       n = m;
+               /* Now move that much data into frame buffer */
+               RingQueue_Dequeue(
+                       &uvd->dp,
+                       frame->data + frame->seqRead_Length,
+                       m);
+               frame->seqRead_Length += m;
+       }
+       /* See if we filled the frame */
+       if (frame->seqRead_Length >= uvd->max_frame_size) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
+{
+       struct usbvideo_frame *frame = &uvd->frame[frameNum];
+
+       if (uvd->debug >= 2)
+               info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
+
+       switch (frame->frameState) {
+       case FrameState_Unused:
+               if (uvd->debug >= 2)
+                       info("%s: FrameState_Unused", __FUNCTION__);
+               return -EINVAL;
+       case FrameState_Ready:
+       case FrameState_Grabbing:
+       case FrameState_Error:
+       {
+               int ntries, signalPending;
+       redo:
+               if (!CAMERA_IS_OPERATIONAL(uvd)) {
+                       if (uvd->debug >= 2)
+                               info("%s: Camera is not operational (1)", __FUNCTION__);
+                       return -EIO;
+               }
+               ntries = 0;
+               do {
+                       RingQueue_InterruptibleSleepOn(&uvd->dp);
+                       signalPending = signal_pending(current);
+                       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+                               if (uvd->debug >= 2)
+                                       info("%s: Camera is not operational (2)", __FUNCTION__);
+                               return -EIO;
+                       }
+                       assert(uvd->fbuf != NULL);
+                       if (signalPending) {
+                               if (uvd->debug >= 2)
+                                       info("%s: Signal=$%08x", __FUNCTION__, signalPending);
+                               if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
+                                       usbvideo_TestPattern(uvd, 1, 0);
+                                       uvd->curframe = -1;
+                                       uvd->stats.frame_num++;
+                                       if (uvd->debug >= 2)
+                                               info("%s: Forced test pattern screen", __FUNCTION__);
+                                       return 0;
+                               } else {
+                                       /* Standard answer: Interrupted! */
+                                       if (uvd->debug >= 2)
+                                               info("%s: Interrupted!", __FUNCTION__);
+                                       return -EINTR;
+                               }
+                       } else {
+                               /* No signals - we just got new data in dp queue */
+                               if (uvd->flags & FLAGS_NO_DECODING)
+                                       usbvideo_CollectRawData(uvd, frame);
+                               else if (VALID_CALLBACK(uvd, processData))
+                                       GET_CALLBACK(uvd, processData)(uvd, frame);
+                               else
+                                       err("%s: processData not set", __FUNCTION__);
+                       }
+               } while (frame->frameState == FrameState_Grabbing);
+               if (uvd->debug >= 2) {
+                       info("%s: Grabbing done; state=%d. (%lu. bytes)",
+                            __FUNCTION__, frame->frameState, frame->seqRead_Length);
+               }
+               if (frame->frameState == FrameState_Error) {
+                       int ret = usbvideo_NewFrame(uvd, frameNum);
+                       if (ret < 0) {
+                               err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
+                               return ret;
+                       }
+                       goto redo;
+               }
+               /* Note that we fall through to meet our destiny below */
+       }
+       case FrameState_Done:
+               /*
+                * Do all necessary postprocessing of data prepared in
+                * "interrupt" code and the collecting code above. The
+                * frame gets marked as FrameState_Done by queue parsing code.
+                * This status means that we collected enough data and
+                * most likely processed it as we went through. However
+                * the data may need postprocessing, such as deinterlacing
+                * or picture adjustments implemented in software (horror!)
+                *
+                * As soon as the frame becomes "final" it gets promoted to
+                * FrameState_Done_Hold status where it will remain until the
+                * caller consumed all the video data from the frame. Then
+                * the empty shell of ex-frame is thrown out for dogs to eat.
+                * But we, worried about pets, will recycle the frame!
+                */
+               uvd->stats.frame_num++;
+               if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
+                       if (VALID_CALLBACK(uvd, postProcess))
+                               GET_CALLBACK(uvd, postProcess)(uvd, frame);
+                       if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
+                               usbvideo_SoftwareContrastAdjustment(uvd, frame);
+               }
+               frame->frameState = FrameState_Done_Hold;
+               if (uvd->debug >= 2)
+                       info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
+               return 0;
+
+       case FrameState_Done_Hold:
+               /*
+                * We stay in this state indefinitely until someone external,
+                * like ioctl() or read() call finishes digesting the frame
+                * data. Then it will mark the frame as FrameState_Unused and
+                * it will be released back into the wild to roam freely.
+                */
+               if (uvd->debug >= 2)
+                       info("%s: FrameState_Done_Hold state.", __FUNCTION__);
+               return 0;
+       }
+
+       /* Catch-all for other cases. We shall not be here. */
+       err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
+       frame->frameState = FrameState_Unused;
+       return 0;
+}
+
+/*
+ * usbvideo_DeinterlaceFrame()
+ *
+ * This procedure deinterlaces the given frame. Some cameras produce
+ * only half of scanlines - sometimes only even lines, sometimes only
+ * odd lines. The deinterlacing method is stored in frame->deinterlace
+ * variable.
+ *
+ * Here we scan the frame vertically and replace missing scanlines with
+ * average between surrounding ones - before and after. If we have no
+ * line above then we just copy next line. Similarly, if we need to
+ * create a last line then preceding line is used.
+ */
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       if ((uvd == NULL) || (frame == NULL))
+               return;
+
+       if ((frame->deinterlace == Deinterlace_FillEvenLines) ||
+           (frame->deinterlace == Deinterlace_FillOddLines))
+       {
+               const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+               int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1;
+
+               for (; i < VIDEOSIZE_Y(frame->request); i += 2) {
+                       const unsigned char *fs1, *fs2;
+                       unsigned char *fd;
+                       int ip, in, j;  /* Previous and next lines */
+
+                       /*
+                        * Need to average lines before and after 'i'.
+                        * If we go out of bounds seeking those lines then
+                        * we point back to existing line.
+                        */
+                       ip = i - 1;     /* First, get rough numbers */
+                       in = i + 1;
+
+                       /* Now validate */
+                       if (ip < 0)
+                               ip = in;
+                       if (in >= VIDEOSIZE_Y(frame->request))
+                               in = ip;
+
+                       /* Sanity check */
+                       if ((ip < 0) || (in < 0) ||
+                           (ip >= VIDEOSIZE_Y(frame->request)) ||
+                           (in >= VIDEOSIZE_Y(frame->request)))
+                       {
+                               err("Error: ip=%d. in=%d. req.height=%ld.",
+                                   ip, in, VIDEOSIZE_Y(frame->request));
+                               break;
+                       }
+
+                       /* Now we need to average lines 'ip' and 'in' to produce line 'i' */
+                       fs1 = frame->data + (v4l_linesize * ip);
+                       fs2 = frame->data + (v4l_linesize * in);
+                       fd = frame->data + (v4l_linesize * i);
+
+                       /* Average lines around destination */
+                       for (j=0; j < v4l_linesize; j++) {
+                               fd[j] = (unsigned char)((((unsigned) fs1[j]) +
+                                                        ((unsigned)fs2[j])) >> 1);
+                       }
+               }
+       }
+
+       /* Optionally display statistics on the screen */
+       if (uvd->flags & FLAGS_OVERLAY_STATS)
+               usbvideo_OverlayStats(uvd, frame);
+}
+
+EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
+
+/*
+ * usbvideo_SoftwareContrastAdjustment()
+ *
+ * This code adjusts the contrast of the frame, assuming RGB24 format.
+ * As most software image processing, this job is CPU-intensive.
+ * Get a camera that supports hardware adjustment!
+ *
+ * History:
+ * 09-Feb-2001  Created.
+ */
+static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
+                                               struct usbvideo_frame *frame)
+{
+       int i, j, v4l_linesize;
+       signed long adj;
+       const int ccm = 128; /* Color correction median - see below */
+
+       if ((uvd == NULL) || (frame == NULL)) {
+               err("%s: Illegal call.", __FUNCTION__);
+               return;
+       }
+       adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(adj, -ccm, ccm+1);
+       if (adj == 0) {
+               /* In rare case of no adjustment */
+               return;
+       }
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+       for (i=0; i < VIDEOSIZE_Y(frame->request); i++) {
+               unsigned char *fd = frame->data + (v4l_linesize * i);
+               for (j=0; j < v4l_linesize; j++) {
+                       signed long v = (signed long) fd[j];
+                       /* Magnify up to 2 times, reduce down to zero */
+                       v = 128 + ((ccm + adj) * (v - 128)) / ccm;
+                       RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */
+                       fd[j] = (unsigned char) v;
+               }
+       }
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h
new file mode 100644 (file)
index 0000000..3cbf4fc
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef usbvideo_h
+#define        usbvideo_h
+
+#include <linux/config.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+/* Most helpful debugging aid */
+#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
+
+#define USBVIDEO_REPORT_STATS  1       /* Set to 0 to block statistics on close */
+
+/* Bit flags (options) */
+#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
+#define        FLAGS_MONOCHROME                (1 << 1)
+#define FLAGS_DISPLAY_HINTS            (1 << 2)
+#define FLAGS_OVERLAY_STATS            (1 << 3)
+#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
+#define FLAGS_SEPARATE_FRAMES          (1 << 5)
+#define FLAGS_CLEAN_FRAMES             (1 << 6)
+#define        FLAGS_NO_DECODING               (1 << 7)
+
+/* Bit flags for frames (apply to the frame where they are specified) */
+#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST  (1 << 0)
+
+/* Camera capabilities (maximum) */
+#define CAMERA_URB_FRAMES       32
+#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
+#define FRAMES_PER_DESC                (CAMERA_URB_FRAMES)
+#define FRAME_SIZE_PER_DESC    (CAMERA_MAX_ISO_PACKET)
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+
+#define V4L_BYTES_PER_PIXEL     3      /* Because we produce RGB24 */
+
+/*
+ * Use this macro to construct constants for different video sizes.
+ * We have to deal with different video sizes that have to be
+ * configured in the device or compared against when we receive
+ * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y
+ * #defines and that's the end of story. However this solution
+ * does not allow to convert between real pixel sizes and the
+ * constant (integer) value that may be used to tag a frame or
+ * whatever. The set of macros below constructs videosize constants
+ * from the pixel size and allows to reconstruct the pixel size
+ * from the combined value later.
+ */
+#define        VIDEOSIZE(x,y)  (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16))
+#define        VIDEOSIZE_X(vs) ((vs) & 0xFFFFL)
+#define        VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL)
+typedef unsigned long videosize_t;
+
+/*
+ * This macro checks if the camera is still operational. The 'uvd'
+ * pointer must be valid, uvd->dev must be valid, we are not
+ * removing the device and the device has not erred on us.
+ */
+#define CAMERA_IS_OPERATIONAL(uvd) (\
+       (uvd != NULL) && \
+       ((uvd)->dev != NULL) && \
+       ((uvd)->last_error == 0) && \
+       (!(uvd)->remove_pending))
+
+/*
+ * We use macros to do YUV -> RGB conversion because this is
+ * very important for speed and totally unimportant for size.
+ *
+ * YUV -> RGB Conversion
+ * ---------------------
+ *
+ * B = 1.164*(Y-16)                + 2.018*(V-128)
+ * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
+ * R = 1.164*(Y-16) + 1.596*(U-128)
+ *
+ * If you fancy integer arithmetics (as you should), hear this:
+ *
+ * 65536*B = 76284*(Y-16)                + 132252*(V-128)
+ * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
+ * 65536*R = 76284*(Y-16) + 104595*(U-128)
+ *
+ * Make sure the output values are within [0..255] range.
+ */
+#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
+#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
+    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+    mm_y = (my) - 16;  \
+    mm_u = (mu) - 128; \
+    mm_v = (mv) - 128; \
+    mm_yc= mm_y * 76284; \
+    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
+    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
+    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
+    mb = LIMIT_RGB(mm_b); \
+    mg = LIMIT_RGB(mm_g); \
+    mr = LIMIT_RGB(mm_r); \
+}
+
+#define        RING_QUEUE_SIZE         (128*1024)      /* Must be a power of 2 */
+#define        RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
+#define        RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
+#define        RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
+
+struct RingQueue {
+       unsigned char *queue;   /* Data from the Isoc data pump */
+       int length;             /* How many bytes allocated for the queue */
+       int wi;                 /* That's where we write */
+       int ri;                 /* Read from here until you hit write index */
+       wait_queue_head_t wqh;  /* Processes waiting */
+};
+
+enum ScanState {
+       ScanState_Scanning,     /* Scanning for header */
+       ScanState_Lines         /* Parsing lines */
+};
+
+/* Completion states of the data parser */
+enum ParseState {
+       scan_Continue,          /* Just parse next item */
+       scan_NextFrame,         /* Frame done, send it to V4L */
+       scan_Out,               /* Not enough data for frame */
+       scan_EndParse           /* End parsing */
+};
+
+enum FrameState {
+       FrameState_Unused,      /* Unused (no MCAPTURE) */
+       FrameState_Ready,       /* Ready to start grabbing */
+       FrameState_Grabbing,    /* In the process of being grabbed into */
+       FrameState_Done,        /* Finished grabbing, but not been synced yet */
+       FrameState_Done_Hold,   /* Are syncing or reading */
+       FrameState_Error,       /* Something bad happened while processing */
+};
+
+/*
+ * Some frames may contain only even or odd lines. This type
+ * specifies what type of deinterlacing is required.
+ */
+enum Deinterlace {
+       Deinterlace_None=0,
+       Deinterlace_FillOddLines,
+       Deinterlace_FillEvenLines
+};
+
+#define USBVIDEO_NUMFRAMES     2       /* How many frames we work with */
+#define USBVIDEO_NUMSBUF       2       /* How many URBs linked in a ring */
+
+/* This structure represents one Isoc request - URB and buffer */
+struct usbvideo_sbuf {
+       char *data;
+       struct urb *urb;
+};
+
+struct usbvideo_frame {
+       char *data;             /* Frame buffer */
+       unsigned long header;   /* Significant bits from the header */
+
+       videosize_t canvas;     /* The canvas (max. image) allocated */
+       videosize_t request;    /* That's what the application asked for */
+       unsigned short palette; /* The desired format */
+
+       enum FrameState frameState;/* State of grabbing */
+       enum ScanState scanstate;       /* State of scanning */
+       enum Deinterlace deinterlace;
+       int flags;              /* USBVIDEO_FRAME_FLAG_xxx bit flags */
+
+       int curline;            /* Line of frame we're working on */
+
+       long seqRead_Length;    /* Raw data length of frame */
+       long seqRead_Index;     /* Amount of data that has been already read */
+
+       void *user;             /* Additional data that user may need */
+};
+
+/* Statistics that can be overlaid on screen */
+struct usbvideo_statistics {
+       unsigned long frame_num;        /* Sequential number of the frame */
+       unsigned long urb_count;        /* How many URBs we received so far */
+       unsigned long urb_length;       /* Length of last URB */
+       unsigned long data_count;       /* How many bytes we received */
+       unsigned long header_count;     /* How many frame headers we found */
+       unsigned long iso_skip_count;   /* How many empty ISO packets received */
+       unsigned long iso_err_count;    /* How many bad ISO packets received */
+};
+
+struct usbvideo;
+
+struct uvd {
+       struct video_device vdev;       /* Must be the first field! */
+       struct usb_device *dev;
+       struct usbvideo *handle;        /* Points back to the struct usbvideo */
+       void *user_data;                /* Camera-dependent data */
+       int user_size;                  /* Size of that camera-dependent data */
+       int debug;                      /* Debug level for usbvideo */
+       unsigned char iface;            /* Video interface number */
+       unsigned char video_endp;
+       unsigned char ifaceAltActive;
+       unsigned char ifaceAltInactive; /* Alt settings */
+       unsigned long flags;            /* FLAGS_USBVIDEO_xxx */
+       unsigned long paletteBits;      /* Which palettes we accept? */
+       unsigned short defaultPalette;  /* What palette to use for read() */
+       struct mutex lock;
+       int user;               /* user count for exclusive use */
+
+       videosize_t videosize;  /* Current setting */
+       videosize_t canvas;     /* This is the width,height of the V4L canvas */
+       int max_frame_size;     /* Bytes in one video frame */
+
+       int uvd_used;           /* Is this structure in use? */
+       int streaming;          /* Are we streaming Isochronous? */
+       int grabbing;           /* Are we grabbing? */
+       int settingsAdjusted;   /* Have we adjusted contrast etc.? */
+       int last_error;         /* What calamity struck us? */
+
+       char *fbuf;             /* Videodev buffer area */
+       int fbuf_size;          /* Videodev buffer size */
+
+       int curframe;
+       int iso_packet_len;     /* Videomode-dependent, saves bus bandwidth */
+
+       struct RingQueue dp;    /* Isoc data pump */
+       struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
+       struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
+
+       volatile int remove_pending;    /* If set then about to exit */
+
+       struct video_picture vpic, vpic_old;    /* Picture settings */
+       struct video_capability vcap;           /* Video capabilities */
+       struct video_channel vchan;     /* May be used for tuner support */
+       struct usbvideo_statistics stats;
+       char videoName[32];             /* Holds name like "video7" */
+};
+
+/*
+ * usbvideo callbacks (virtual methods). They are set when usbvideo
+ * services are registered. All of these default to NULL, except those
+ * that default to usbvideo-provided methods.
+ */
+struct usbvideo_cb {
+       int (*probe)(struct usb_interface *, const struct usb_device_id *);
+       void (*userFree)(struct uvd *);
+       void (*disconnect)(struct usb_interface *);
+       int (*setupOnOpen)(struct uvd *);
+       void (*videoStart)(struct uvd *);
+       void (*videoStop)(struct uvd *);
+       void (*processData)(struct uvd *, struct usbvideo_frame *);
+       void (*postProcess)(struct uvd *, struct usbvideo_frame *);
+       void (*adjustPicture)(struct uvd *);
+       int (*getFPS)(struct uvd *);
+       int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
+       int (*getFrame)(struct uvd *, int);
+       int (*startDataPump)(struct uvd *uvd);
+       void (*stopDataPump)(struct uvd *uvd);
+       int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
+};
+
+struct usbvideo {
+       int num_cameras;                /* As allocated */
+       struct usb_driver usbdrv;       /* Interface to the USB stack */
+       char drvName[80];               /* Driver name */
+       struct mutex lock;              /* Mutex protecting camera structures */
+       struct usbvideo_cb cb;          /* Table of callbacks (virtual methods) */
+       struct video_device vdt;        /* Video device template */
+       struct uvd *cam;                        /* Array of camera structures */
+       struct module *md_module;       /* Minidriver module */
+};
+
+
+/*
+ * This macro retrieves callback address from the struct uvd object.
+ * No validity checks are done here, so be sure to check the
+ * callback beforehand with VALID_CALLBACK.
+ */
+#define        GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName)
+
+/*
+ * This macro returns either callback pointer or NULL. This is safe
+ * macro, meaning that most of components of data structures involved
+ * may be NULL - this only results in NULL being returned. You may
+ * wish to use this macro to make sure that the callback is callable.
+ * However keep in mind that those checks take time.
+ */
+#define        VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
+               ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
+
+int  RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
+int  RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
+void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
+void RingQueue_Flush(struct RingQueue *rq);
+
+static inline int RingQueue_GetLength(const struct RingQueue *rq)
+{
+       return (rq->wi - rq->ri + rq->length) & (rq->length-1);
+}
+
+static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
+{
+       return rq->length - RingQueue_GetLength(rq);
+}
+
+void usbvideo_DrawLine(
+       struct usbvideo_frame *frame,
+       int x1, int y1,
+       int x2, int y2,
+       unsigned char cr, unsigned char cg, unsigned char cb);
+void usbvideo_HexDump(const unsigned char *data, int len);
+void usbvideo_SayAndWait(const char *what);
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
+
+/* Memory allocation routines */
+unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
+
+int usbvideo_register(
+       struct usbvideo **pCams,
+       const int num_cams,
+       const int num_extra,
+       const char *driverName,
+       const struct usbvideo_cb *cbTable,
+       struct module *md,
+       const struct usb_device_id *id_table);
+struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
+int usbvideo_RegisterVideoDevice(struct uvd *uvd);
+void usbvideo_Deregister(struct usbvideo **uvt);
+
+int usbvideo_v4l_initialize(struct video_device *dev);
+
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
+
+/*
+ * This code performs bounds checking - use it when working with
+ * new formats, or else you may get oopses all over the place.
+ * If pixel falls out of bounds then it gets shoved back (as close
+ * to place of offence as possible) and is painted bright red.
+ *
+ * There are two important concepts: frame width, height and
+ * V4L canvas width, height. The former is the area requested by
+ * the application -for this very frame-. The latter is the largest
+ * possible frame that we can serve (we advertise that via V4L ioctl).
+ * The frame data is expected to be formatted as lines of length
+ * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
+ */
+static inline void RGB24_PUTPIXEL(
+       struct usbvideo_frame *fr,
+       int ix, int iy,
+       unsigned char vr,
+       unsigned char vg,
+       unsigned char vb)
+{
+       register unsigned char *pf;
+       int limiter = 0, mx, my;
+       mx = ix;
+       my = iy;
+       if (mx < 0) {
+               mx=0;
+               limiter++;
+       } else if (mx >= VIDEOSIZE_X((fr)->request)) {
+               mx= VIDEOSIZE_X((fr)->request) - 1;
+               limiter++;
+       }
+       if (my < 0) {
+               my = 0;
+               limiter++;
+       } else if (my >= VIDEOSIZE_Y((fr)->request)) {
+               my = VIDEOSIZE_Y((fr)->request) - 1;
+               limiter++;
+       }
+       pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix));
+       if (limiter) {
+               *pf++ = 0;
+               *pf++ = 0;
+               *pf++ = 0xFF;
+       } else {
+               *pf++ = (vb);
+               *pf++ = (vg);
+               *pf++ = (vr);
+       }
+}
+
+#endif /* usbvideo_h */
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
new file mode 100644 (file)
index 0000000..90d48e8
--- /dev/null
@@ -0,0 +1,1411 @@
+/*
+ * USB ViCam WebCam driver
+ * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
+ *                    Christopher L Cheney (ccheney@cheney.cx),
+ *                    Pavel Machek (pavel@suse.cz),
+ *                    John Tyner (jtyner@cs.ucr.edu),
+ *                    Monroe Williams (monroe@pobox.com)
+ *
+ * Supports 3COM HomeConnect PC Digital WebCam
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This source code is based heavily on the CPiA webcam driver which was
+ * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
+ *
+ * Portions of this code were also copied from usbvideo.c
+ *
+ * Special thanks to the the whole team at Sourceforge for help making
+ * this driver become a reality.  Notably:
+ * Andy Armstrong who reverse engineered the color encoding and
+ * Pavel Machek and Chris Cheney who worked on reverse engineering the
+ *    camera controls and wrote the first generation driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include "usbvideo.h"
+
+// #define VICAM_DEBUG
+
+#ifdef VICAM_DEBUG
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
+#define DRIVER_DESC             "ViCam WebCam Driver"
+
+/* Define these values to match your device */
+#define USB_VICAM_VENDOR_ID    0x04c1
+#define USB_VICAM_PRODUCT_ID   0x009d
+
+#define VICAM_BYTES_PER_PIXEL   3
+#define VICAM_MAX_READ_SIZE     (512*242+128)
+#define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
+#define VICAM_FRAMES            2
+
+#define VICAM_HEADER_SIZE       64
+
+#define clamp( x, l, h )        max_t( __typeof__( x ),         \
+                                      ( l ),                   \
+                                      min_t( __typeof__( x ),  \
+                                             ( h ),            \
+                                             ( x ) ) )
+
+/* Not sure what all the bytes in these char
+ * arrays do, but they're necessary to make
+ * the camera work.
+ */
+
+static unsigned char setup1[] = {
+       0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
+       0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
+       0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
+       0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
+       0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
+};
+
+static unsigned char setup2[] = {
+       0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
+       0x00, 0x00
+};
+
+static unsigned char setup3[] = {
+       0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
+};
+
+static unsigned char setup4[] = {
+       0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
+       0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+       0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
+       0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
+       0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
+       0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
+       0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
+       0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
+       0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
+       0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
+       0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
+       0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
+       0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
+       0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
+       0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
+       0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
+       0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
+       0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
+       0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
+       0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
+       0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
+       0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
+       0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
+       0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
+       0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
+       0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
+       0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
+       0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
+       0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
+       0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
+       0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
+       0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
+       0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+       0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
+       0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
+       0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
+       0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
+       0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
+       0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
+       0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
+       0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
+       0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
+       0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+       0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
+       0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
+       0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
+       0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
+       0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
+       0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
+       0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
+       0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
+       0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
+       0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
+       0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
+       0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+       0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
+       0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
+       0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+       0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
+       0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
+       0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
+       0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
+       0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
+       0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
+       0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
+       0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+       0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+       0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
+       0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+       0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
+       0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
+       0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+       0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+       0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
+       0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
+       0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
+       0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
+       0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
+       0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
+       0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
+       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
+       0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
+       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+       0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
+       0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
+       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
+       0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
+       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+       0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
+       0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
+       0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
+       0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+       0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
+       0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+       0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
+       0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
+       0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
+       0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
+       0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
+       0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
+       0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
+       0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
+       0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
+       0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
+       0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
+       0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
+       0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
+       0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
+       0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
+       0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
+       0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+       0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+       0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+       0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
+       0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
+       0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
+       0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
+       0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
+       0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+       0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
+       0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
+       0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
+       0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
+       0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+       0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+       0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
+       0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
+       0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
+       0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
+       0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+       0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
+       0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
+       0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
+       0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+       0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
+       0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
+       0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
+       0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
+       0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
+       0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
+       0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
+       0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
+       0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+       0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
+       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
+       0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
+       0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
+       0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+       0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
+       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
+       0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+       0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
+       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
+       0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+       0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
+       0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
+       0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
+       0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
+       0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
+       0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
+       0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
+       0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
+       0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
+       0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+       0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
+       0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+       0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+       0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
+       0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+       0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+       0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+       0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
+       0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
+       0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+       0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+       0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
+       0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+       0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
+       0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
+       0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+       0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+       0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
+       0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
+       0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+       0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static unsigned char setup5[] = {
+       0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
+       0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
+       0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
+       0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
+       0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
+       0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
+       0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
+       0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
+       0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
+       0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
+       0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
+       0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
+       0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
+       0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
+       0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
+       0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
+       0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
+       0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
+       0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
+       0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
+       0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
+       0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
+       0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
+       0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
+       0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
+       0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
+       0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
+       0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
+       0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
+       0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
+       0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
+       0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
+       0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
+       0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
+       0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
+       0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
+       0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
+       0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
+       0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
+
+/* rvmalloc / rvfree copied from usbvideo.c
+ *
+ * Not sure why these are not yet non-statics which I can reference through
+ * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
+ * in the future.
+ *
+*/
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+struct vicam_camera {
+       u16 shutter_speed;      // capture shutter speed
+       u16 gain;               // capture gain
+
+       u8 *raw_image;          // raw data captured from the camera
+       u8 *framebuf;           // processed data in RGB24 format
+       u8 *cntrlbuf;           // area used to send control msgs
+
+       struct video_device vdev;       // v4l video device
+       struct usb_device *udev;        // usb device
+
+       /* guard against simultaneous accesses to the camera */
+       struct mutex cam_lock;
+
+       int is_initialized;
+       u8 open_count;
+       u8 bulkEndpoint;
+       int needsDummyRead;
+
+#if defined(CONFIG_VIDEO_PROC_FS)
+       struct proc_dir_entry *proc_dir;
+#endif
+
+};
+
+static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
+static void vicam_disconnect(struct usb_interface *intf);
+static void read_frame(struct vicam_camera *cam, int framenum);
+static void vicam_decode_color(const u8 *, u8 *);
+
+static int __send_control_msg(struct vicam_camera *cam,
+                             u8 request,
+                             u16 value,
+                             u16 index,
+                             unsigned char *cp,
+                             u16 size)
+{
+       int status;
+
+       /* cp must be memory that has been allocated by kmalloc */
+
+       status = usb_control_msg(cam->udev,
+                                usb_sndctrlpipe(cam->udev, 0),
+                                request,
+                                USB_DIR_OUT | USB_TYPE_VENDOR |
+                                USB_RECIP_DEVICE, value, index,
+                                cp, size, 1000);
+
+       status = min(status, 0);
+
+       if (status < 0) {
+               printk(KERN_INFO "Failed sending control message, error %d.\n",
+                      status);
+       }
+
+       return status;
+}
+
+static int send_control_msg(struct vicam_camera *cam,
+                           u8 request,
+                           u16 value,
+                           u16 index,
+                           unsigned char *cp,
+                           u16 size)
+{
+       int status = -ENODEV;
+       mutex_lock(&cam->cam_lock);
+       if (cam->udev) {
+               status = __send_control_msg(cam, request, value,
+                                           index, cp, size);
+       }
+       mutex_unlock(&cam->cam_lock);
+       return status;
+}
+static int
+initialize_camera(struct vicam_camera *cam)
+{
+       const struct {
+               u8 *data;
+               u32 size;
+       } firmware[] = {
+               { .data = setup1, .size = sizeof(setup1) },
+               { .data = setup2, .size = sizeof(setup2) },
+               { .data = setup3, .size = sizeof(setup3) },
+               { .data = setup4, .size = sizeof(setup4) },
+               { .data = setup5, .size = sizeof(setup5) },
+               { .data = setup3, .size = sizeof(setup3) },
+               { .data = NULL, .size = 0 }
+       };
+
+       int err, i;
+
+       for (i = 0, err = 0; firmware[i].data && !err; i++) {
+               memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
+
+               err = send_control_msg(cam, 0xff, 0, 0,
+                                      cam->cntrlbuf, firmware[i].size);
+       }
+
+       return err;
+}
+
+static int
+set_camera_power(struct vicam_camera *cam, int state)
+{
+       int status;
+
+       if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
+               return status;
+
+       if (state) {
+               send_control_msg(cam, 0x55, 1, 0, NULL, 0);
+       }
+
+       return 0;
+}
+
+static int
+vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
+{
+       void __user *user_arg = (void __user *)arg;
+       struct vicam_camera *cam = file->private_data;
+       int retval = 0;
+
+       if (!cam)
+               return -ENODEV;
+
+       switch (ioctlnr) {
+               /* query capabilities */
+       case VIDIOCGCAP:
+               {
+                       struct video_capability b;
+
+                       DBG("VIDIOCGCAP\n");
+                       memset(&b, 0, sizeof(b));
+                       strcpy(b.name, "ViCam-based Camera");
+                       b.type = VID_TYPE_CAPTURE;
+                       b.channels = 1;
+                       b.audios = 0;
+                       b.maxwidth = 320;       /* VIDEOSIZE_CIF */
+                       b.maxheight = 240;
+                       b.minwidth = 320;       /* VIDEOSIZE_48_48 */
+                       b.minheight = 240;
+
+                       if (copy_to_user(user_arg, &b, sizeof(b)))
+                               retval = -EFAULT;
+
+                       break;
+               }
+               /* get/set video source - we are a camera and nothing else */
+       case VIDIOCGCHAN:
+               {
+                       struct video_channel v;
+
+                       DBG("VIDIOCGCHAN\n");
+                       if (copy_from_user(&v, user_arg, sizeof(v))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+                       if (v.channel != 0) {
+                               retval = -EINVAL;
+                               break;
+                       }
+
+                       v.channel = 0;
+                       strcpy(v.name, "Camera");
+                       v.tuners = 0;
+                       v.flags = 0;
+                       v.type = VIDEO_TYPE_CAMERA;
+                       v.norm = 0;
+
+                       if (copy_to_user(user_arg, &v, sizeof(v)))
+                               retval = -EFAULT;
+                       break;
+               }
+
+       case VIDIOCSCHAN:
+               {
+                       int v;
+
+                       if (copy_from_user(&v, user_arg, sizeof(v)))
+                               retval = -EFAULT;
+                       DBG("VIDIOCSCHAN %d\n", v);
+
+                       if (retval == 0 && v != 0)
+                               retval = -EINVAL;
+
+                       break;
+               }
+
+               /* image properties */
+       case VIDIOCGPICT:
+               {
+                       struct video_picture vp;
+                       DBG("VIDIOCGPICT\n");
+                       memset(&vp, 0, sizeof (struct video_picture));
+                       vp.brightness = cam->gain << 8;
+                       vp.depth = 24;
+                       vp.palette = VIDEO_PALETTE_RGB24;
+                       if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
+                               retval = -EFAULT;
+                       break;
+               }
+
+       case VIDIOCSPICT:
+               {
+                       struct video_picture vp;
+
+                       if (copy_from_user(&vp, user_arg, sizeof(vp))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+
+                       DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
+                           vp.palette);
+
+                       cam->gain = vp.brightness >> 8;
+
+                       if (vp.depth != 24
+                           || vp.palette != VIDEO_PALETTE_RGB24)
+                               retval = -EINVAL;
+
+                       break;
+               }
+
+               /* get/set capture window */
+       case VIDIOCGWIN:
+               {
+                       struct video_window vw;
+                       vw.x = 0;
+                       vw.y = 0;
+                       vw.width = 320;
+                       vw.height = 240;
+                       vw.chromakey = 0;
+                       vw.flags = 0;
+                       vw.clips = NULL;
+                       vw.clipcount = 0;
+
+                       DBG("VIDIOCGWIN\n");
+
+                       if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
+                               retval = -EFAULT;
+
+                       // I'm not sure what the deal with a capture window is, it is very poorly described
+                       // in the doc.  So I won't support it now.
+                       break;
+               }
+
+       case VIDIOCSWIN:
+               {
+
+                       struct video_window vw;
+
+                       if (copy_from_user(&vw, user_arg, sizeof(vw))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+
+                       DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
+
+                       if ( vw.width != 320 || vw.height != 240 )
+                               retval = -EFAULT;
+
+                       break;
+               }
+
+               /* mmap interface */
+       case VIDIOCGMBUF:
+               {
+                       struct video_mbuf vm;
+                       int i;
+
+                       DBG("VIDIOCGMBUF\n");
+                       memset(&vm, 0, sizeof (vm));
+                       vm.size =
+                           VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
+                       vm.frames = VICAM_FRAMES;
+                       for (i = 0; i < VICAM_FRAMES; i++)
+                               vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
+
+                       if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
+                               retval = -EFAULT;
+
+                       break;
+               }
+
+       case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap vm;
+                       // int video_size;
+
+                       if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+
+                       DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
+
+                       if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
+                               retval = -EINVAL;
+
+                       // in theory right here we'd start the image capturing
+                       // (fill in a bulk urb and submit it asynchronously)
+                       //
+                       // Instead we're going to do a total hack job for now and
+                       // retrieve the frame in VIDIOCSYNC
+
+                       break;
+               }
+
+       case VIDIOCSYNC:
+               {
+                       int frame;
+
+                       if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+                       DBG("VIDIOCSYNC: %d\n", frame);
+
+                       read_frame(cam, frame);
+                       vicam_decode_color(cam->raw_image,
+                                          cam->framebuf +
+                                          frame * VICAM_MAX_FRAME_SIZE );
+
+                       break;
+               }
+
+               /* pointless to implement overlay with this camera */
+       case VIDIOCCAPTURE:
+       case VIDIOCGFBUF:
+       case VIDIOCSFBUF:
+       case VIDIOCKEY:
+               retval = -EINVAL;
+               break;
+
+               /* tuner interface - we have none */
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+               retval = -EINVAL;
+               break;
+
+               /* audio interface - we have none */
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               retval = -EINVAL;
+               break;
+       default:
+               retval = -ENOIOCTLCMD;
+               break;
+       }
+
+       return retval;
+}
+
+static int
+vicam_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vicam_camera *cam =
+           (struct vicam_camera *) dev->priv;
+       DBG("open\n");
+
+       if (!cam) {
+               printk(KERN_ERR
+                      "vicam video_device improperly initialized");
+               return -EINVAL;
+       }
+
+       /* the videodev_lock held above us protects us from
+        * simultaneous opens...for now. we probably shouldn't
+        * rely on this fact forever.
+        */
+
+       if (cam->open_count > 0) {
+               printk(KERN_INFO
+                      "vicam_open called on already opened camera");
+               return -EBUSY;
+       }
+
+       cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
+       if (!cam->raw_image) {
+               return -ENOMEM;
+       }
+
+       cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+       if (!cam->framebuf) {
+               kfree(cam->raw_image);
+               return -ENOMEM;
+       }
+
+       cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!cam->cntrlbuf) {
+               kfree(cam->raw_image);
+               rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+               return -ENOMEM;
+       }
+
+       // First upload firmware, then turn the camera on
+
+       if (!cam->is_initialized) {
+               initialize_camera(cam);
+
+               cam->is_initialized = 1;
+       }
+
+       set_camera_power(cam, 1);
+
+       cam->needsDummyRead = 1;
+       cam->open_count++;
+
+       file->private_data = cam;
+
+       return 0;
+}
+
+static int
+vicam_close(struct inode *inode, struct file *file)
+{
+       struct vicam_camera *cam = file->private_data;
+       int open_count;
+       struct usb_device *udev;
+
+       DBG("close\n");
+
+       /* it's not the end of the world if
+        * we fail to turn the camera off.
+        */
+
+       set_camera_power(cam, 0);
+
+       kfree(cam->raw_image);
+       rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+       kfree(cam->cntrlbuf);
+
+       mutex_lock(&cam->cam_lock);
+
+       cam->open_count--;
+       open_count = cam->open_count;
+       udev = cam->udev;
+
+       mutex_unlock(&cam->cam_lock);
+
+       if (!open_count && !udev) {
+               kfree(cam);
+       }
+
+       return 0;
+}
+
+static void vicam_decode_color(const u8 *data, u8 *rgb)
+{
+       /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
+        * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
+        */
+
+       int i, prevY, nextY;
+
+       prevY = 512;
+       nextY = 512;
+
+       data += VICAM_HEADER_SIZE;
+
+       for( i = 0; i < 240; i++, data += 512 ) {
+               const int y = ( i * 242 ) / 240;
+
+               int j, prevX, nextX;
+               int Y, Cr, Cb;
+
+               if ( y == 242 - 1 ) {
+                       nextY = -512;
+               }
+
+               prevX = 1;
+               nextX = 1;
+
+               for ( j = 0; j < 320; j++, rgb += 3 ) {
+                       const int x = ( j * 512 ) / 320;
+                       const u8 * const src = &data[x];
+
+                       if ( x == 512 - 1 ) {
+                               nextX = -1;
+                       }
+
+                       Cr = ( src[prevX] - src[0] ) +
+                               ( src[nextX] - src[0] );
+                       Cr /= 2;
+
+                       Cb = ( src[prevY] - src[prevX + prevY] ) +
+                               ( src[prevY] - src[nextX + prevY] ) +
+                               ( src[nextY] - src[prevX + nextY] ) +
+                               ( src[nextY] - src[nextX + nextY] );
+                       Cb /= 4;
+
+                       Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
+
+                       if ( i & 1 ) {
+                               int Ct = Cr;
+                               Cr = Cb;
+                               Cb = Ct;
+                       }
+
+                       if ( ( x ^ i ) & 1 ) {
+                               Cr = -Cr;
+                               Cb = -Cb;
+                       }
+
+                       rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
+                                       500 ) / 900, 0, 255 );
+                       rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
+                                         ( 813 * Cr ) ) +
+                                         500 ) / 1000, 0, 255 );
+                       rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
+                                       500 ) / 1300, 0, 255 );
+
+                       prevX = -1;
+               }
+
+               prevY = -512;
+       }
+}
+
+static void
+read_frame(struct vicam_camera *cam, int framenum)
+{
+       unsigned char *request = cam->cntrlbuf;
+       int realShutter;
+       int n;
+       int actual_length;
+
+       if (cam->needsDummyRead) {
+               cam->needsDummyRead = 0;
+               read_frame(cam, framenum);
+       }
+
+       memset(request, 0, 16);
+       request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
+
+       request[1] = 0; // 512x242 capture
+
+       request[2] = 0x90;      // the function of these two bytes
+       request[3] = 0x07;      // is not yet understood
+
+       if (cam->shutter_speed > 60) {
+               // Short exposure
+               realShutter =
+                   ((-15631900 / cam->shutter_speed) + 260533) / 1000;
+               request[4] = realShutter & 0xFF;
+               request[5] = (realShutter >> 8) & 0xFF;
+               request[6] = 0x03;
+               request[7] = 0x01;
+       } else {
+               // Long exposure
+               realShutter = 15600 / cam->shutter_speed - 1;
+               request[4] = 0;
+               request[5] = 0;
+               request[6] = realShutter & 0xFF;
+               request[7] = realShutter >> 8;
+       }
+
+       // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
+       request[8] = 0;
+       // bytes 9-15 do not seem to affect exposure or image quality
+
+       mutex_lock(&cam->cam_lock);
+
+       if (!cam->udev) {
+               goto done;
+       }
+
+       n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
+
+       if (n < 0) {
+               printk(KERN_ERR
+                      " Problem sending frame capture control message");
+               goto done;
+       }
+
+       n = usb_bulk_msg(cam->udev,
+                        usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
+                        cam->raw_image,
+                        512 * 242 + 128, &actual_length, 10000);
+
+       if (n < 0) {
+               printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
+                      n);
+       }
+
+ done:
+       mutex_unlock(&cam->cam_lock);
+}
+
+static ssize_t
+vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
+{
+       struct vicam_camera *cam = file->private_data;
+
+       DBG("read %d bytes.\n", (int) count);
+
+       if (*ppos >= VICAM_MAX_FRAME_SIZE) {
+               *ppos = 0;
+               return 0;
+       }
+
+       if (*ppos == 0) {
+               read_frame(cam, 0);
+               vicam_decode_color(cam->raw_image,
+                                  cam->framebuf +
+                                  0 * VICAM_MAX_FRAME_SIZE);
+       }
+
+       count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
+
+       if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
+               count = -EFAULT;
+       } else {
+               *ppos += count;
+       }
+
+       if (count == VICAM_MAX_FRAME_SIZE) {
+               *ppos = 0;
+       }
+
+       return count;
+}
+
+
+static int
+vicam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       // TODO: allocate the raw frame buffer if necessary
+       unsigned long page, pos;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       struct vicam_camera *cam = file->private_data;
+
+       if (!cam)
+               return -ENODEV;
+
+       DBG("vicam_mmap: %ld\n", size);
+
+       /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
+        * to the size the application requested for mmap and it was screwing apps up.
+        if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
+        return -EINVAL;
+        */
+
+       pos = (unsigned long)cam->framebuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *vicam_proc_root = NULL;
+
+static int vicam_read_helper(char *page, char **start, off_t off,
+                               int count, int *eof, int value)
+{
+       char *out = page;
+       int len;
+
+       out += sprintf(out, "%d",value);
+
+       len = out - page;
+       len -= off;
+       if (len < count) {
+               *eof = 1;
+               if (len <= 0)
+                       return 0;
+       } else
+               len = count;
+
+       *start = page + off;
+       return len;
+}
+
+static int vicam_read_proc_shutter(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       return vicam_read_helper(page,start,off,count,eof,
+                               ((struct vicam_camera *)data)->shutter_speed);
+}
+
+static int vicam_read_proc_gain(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       return vicam_read_helper(page,start,off,count,eof,
+                               ((struct vicam_camera *)data)->gain);
+}
+
+static int
+vicam_write_proc_shutter(struct file *file, const char *buffer,
+                        unsigned long count, void *data)
+{
+       u16 stmp;
+       char kbuf[8];
+       struct vicam_camera *cam = (struct vicam_camera *) data;
+
+       if (count > 6)
+               return -EINVAL;
+
+       if (copy_from_user(kbuf, buffer, count))
+               return -EFAULT;
+
+       stmp = (u16) simple_strtoul(kbuf, NULL, 10);
+       if (stmp < 4 || stmp > 32000)
+               return -EINVAL;
+
+       cam->shutter_speed = stmp;
+
+       return count;
+}
+
+static int
+vicam_write_proc_gain(struct file *file, const char *buffer,
+                     unsigned long count, void *data)
+{
+       u16 gtmp;
+       char kbuf[8];
+
+       struct vicam_camera *cam = (struct vicam_camera *) data;
+
+       if (count > 4)
+               return -EINVAL;
+
+       if (copy_from_user(kbuf, buffer, count))
+               return -EFAULT;
+
+       gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
+       if (gtmp > 255)
+               return -EINVAL;
+       cam->gain = gtmp;
+
+       return count;
+}
+
+static void
+vicam_create_proc_root(void)
+{
+       vicam_proc_root = proc_mkdir("video/vicam", NULL);
+
+       if (vicam_proc_root)
+               vicam_proc_root->owner = THIS_MODULE;
+       else
+               printk(KERN_ERR
+                      "could not create /proc entry for vicam!");
+}
+
+static void
+vicam_destroy_proc_root(void)
+{
+       if (vicam_proc_root)
+               remove_proc_entry("video/vicam", 0);
+}
+
+static void
+vicam_create_proc_entry(struct vicam_camera *cam)
+{
+       char name[64];
+       struct proc_dir_entry *ent;
+
+       DBG(KERN_INFO "vicam: creating proc entry\n");
+
+       if (!vicam_proc_root || !cam) {
+               printk(KERN_INFO
+                      "vicam: could not create proc entry, %s pointer is null.\n",
+                      (!cam ? "camera" : "root"));
+               return;
+       }
+
+       sprintf(name, "video%d", cam->vdev.minor);
+
+       cam->proc_dir = proc_mkdir(name, vicam_proc_root);
+
+       if ( !cam->proc_dir )
+               return; // FIXME: We should probably return an error here
+
+       ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
+                               cam->proc_dir);
+       if (ent) {
+               ent->data = cam;
+               ent->read_proc = vicam_read_proc_shutter;
+               ent->write_proc = vicam_write_proc_shutter;
+               ent->size = 64;
+       }
+
+       ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
+                               cam->proc_dir);
+       if (ent) {
+               ent->data = cam;
+               ent->read_proc = vicam_read_proc_gain;
+               ent->write_proc = vicam_write_proc_gain;
+               ent->size = 64;
+       }
+}
+
+static void
+vicam_destroy_proc_entry(void *ptr)
+{
+       struct vicam_camera *cam = (struct vicam_camera *) ptr;
+       char name[16];
+
+       if ( !cam->proc_dir )
+               return;
+
+       sprintf(name, "video%d", cam->vdev.minor);
+       remove_proc_entry("shutter", cam->proc_dir);
+       remove_proc_entry("gain", cam->proc_dir);
+       remove_proc_entry(name,vicam_proc_root);
+       cam->proc_dir = NULL;
+
+}
+
+#else
+static inline void vicam_create_proc_root(void) { }
+static inline void vicam_destroy_proc_root(void) { }
+static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
+static inline void vicam_destroy_proc_entry(void *ptr) { }
+#endif
+
+static struct file_operations vicam_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vicam_open,
+       .release        = vicam_close,
+       .read           = vicam_read,
+       .mmap           = vicam_mmap,
+       .ioctl          = vicam_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
+       .llseek         = no_llseek,
+};
+
+static struct video_device vicam_template = {
+       .owner          = THIS_MODULE,
+       .name           = "ViCam-based USB Camera",
+       .type           = VID_TYPE_CAPTURE,
+       .hardware       = VID_HARDWARE_VICAM,
+       .fops           = &vicam_fops,
+       .minor          = -1,
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table[] = {
+       {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, vicam_table);
+
+static struct usb_driver vicam_driver = {
+       .name           = "vicam",
+       .probe          = vicam_probe,
+       .disconnect     = vicam_disconnect,
+       .id_table       = vicam_table
+};
+
+/**
+ *     vicam_probe
+ *     @intf: the interface
+ *     @id: the device id
+ *
+ *     Called by the usb core when a new device is connected that it thinks
+ *     this driver might be interested in.
+ */
+static int
+vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       int bulkEndpoint = 0;
+       const struct usb_host_interface *interface;
+       const struct usb_endpoint_descriptor *endpoint;
+       struct vicam_camera *cam;
+
+       printk(KERN_INFO "ViCam based webcam connected\n");
+
+       interface = intf->cur_altsetting;
+
+       DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
+              interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
+       endpoint = &interface->endpoint[0].desc;
+
+       if ((endpoint->bEndpointAddress & 0x80) &&
+           ((endpoint->bmAttributes & 3) == 0x02)) {
+               /* we found a bulk in endpoint */
+               bulkEndpoint = endpoint->bEndpointAddress;
+       } else {
+               printk(KERN_ERR
+                      "No bulk in endpoint was found ?! (this is bad)\n");
+       }
+
+       if ((cam =
+            kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+               printk(KERN_WARNING
+                      "could not allocate kernel memory for vicam_camera struct\n");
+               return -ENOMEM;
+       }
+
+       memset(cam, 0, sizeof (struct vicam_camera));
+
+       cam->shutter_speed = 15;
+
+       mutex_init(&cam->cam_lock);
+
+       memcpy(&cam->vdev, &vicam_template,
+              sizeof (vicam_template));
+       cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
+
+       cam->udev = dev;
+       cam->bulkEndpoint = bulkEndpoint;
+
+       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+               kfree(cam);
+               printk(KERN_WARNING "video_register_device failed\n");
+               return -EIO;
+       }
+
+       vicam_create_proc_entry(cam);
+
+       printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
+
+       usb_set_intfdata (intf, cam);
+
+       return 0;
+}
+
+static void
+vicam_disconnect(struct usb_interface *intf)
+{
+       int open_count;
+       struct vicam_camera *cam = usb_get_intfdata (intf);
+       usb_set_intfdata (intf, NULL);
+
+       /* we must unregister the device before taking its
+        * cam_lock. This is because the video open call
+        * holds the same lock as video unregister. if we
+        * unregister inside of the cam_lock and open also
+        * uses the cam_lock, we get deadlock.
+        */
+
+       video_unregister_device(&cam->vdev);
+
+       /* stop the camera from being used */
+
+       mutex_lock(&cam->cam_lock);
+
+       /* mark the camera as gone */
+
+       cam->udev = NULL;
+
+       vicam_destroy_proc_entry(cam);
+
+       /* the only thing left to do is synchronize with
+        * our close/release function on who should release
+        * the camera memory. if there are any users using the
+        * camera, it's their job. if there are no users,
+        * it's ours.
+        */
+
+       open_count = cam->open_count;
+
+       mutex_unlock(&cam->cam_lock);
+
+       if (!open_count) {
+               kfree(cam);
+       }
+
+       printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
+}
+
+/*
+ */
+static int __init
+usb_vicam_init(void)
+{
+       int retval;
+       DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
+       vicam_create_proc_root();
+       retval = usb_register(&vicam_driver);
+       if (retval)
+               printk(KERN_WARNING "usb_register failed!\n");
+       return retval;
+}
+
+static void __exit
+usb_vicam_exit(void)
+{
+       DBG(KERN_INFO
+              "ViCam-based WebCam driver shutdown\n");
+
+       usb_deregister(&vicam_driver);
+       vicam_destroy_proc_root();
+}
+
+module_init(usb_vicam_init);
+module_exit(usb_vicam_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
index 95a6e47c99f185f41d2165d554b6cefb4379beca..11a97f30b8764e1c67698f5851c9a6f45002813b 100644 (file)
@@ -312,8 +312,6 @@ static const char *v4l2_int_ioctls[] = {
        [_IOC_NR(DECODER_DUMP)]                = "DECODER_DUMP",
 #endif
        [_IOC_NR(AUDC_SET_RADIO)]              = "AUDC_SET_RADIO",
-       [_IOC_NR(AUDC_SET_INPUT)]              = "AUDC_SET_INPUT",
-       [_IOC_NR(MSP_SET_MATRIX)]              = "MSP_SET_MATRIX",
 
        [_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
        [_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
@@ -419,7 +417,6 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        case TUNER_SET_TYPE_ADDR:
        case TUNER_SET_STANDBY:
        case TDA9887_SET_CONFIG:
-       case AUDC_SET_INPUT:
        case VIDIOC_OVERLAY_OLD:
        case VIDIOC_STREAMOFF:
        case VIDIOC_G_OUTPUT:
@@ -433,12 +430,6 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
                printk ("%s: value=%d\n", s, *p);
                break;
        }
-       case MSP_SET_MATRIX:
-       {
-               struct msp_matrix *p=arg;
-               printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
-               break;
-       }
        case VIDIOC_G_AUDIO:
        case VIDIOC_S_AUDIO:
        case VIDIOC_ENUMAUDIO:
@@ -467,7 +458,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
                struct v4l2_buffer *p=arg;
                struct v4l2_timecode *tc=&p->timecode;
                printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
-                       "bytesused=%d, flags=0x%08d, "
+                       "bytesused=%d, flags=0x%08x, "
                        "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
                                s,
                                (p->timestamp.tv_sec/3600),
@@ -481,16 +472,16 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
                                prt_names(p->memory,v4l2_memory_names),
                                p->m.userptr);
                printk ("%s: timecode= %02d:%02d:%02d type=%d, "
-                       "flags=0x%08d, frames=%d, userbits=0x%08x",
+                       "flags=0x%08x, frames=%d, userbits=0x%p\n",
                                s,tc->hours,tc->minutes,tc->seconds,
-                               tc->type, tc->flags, tc->frames, (__u32) tc->userbits);
+                               tc->type, tc->flags, tc->frames, tc->userbits);
                break;
        }
        case VIDIOC_QUERYCAP:
        {
                struct v4l2_capability *p=arg;
-               printk ("%s: driver=%s, card=%s, bus=%s, version=%d, "
-                       "capabilities=%d\n", s,
+               printk ("%s: driver=%s, card=%s, bus=%s, version=0x%08x, "
+                       "capabilities=0x%08x\n", s,
                                p->driver,p->card,p->bus_info,
                                p->version,
                                p->capabilities);
@@ -574,9 +565,10 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        {
                struct v4l2_input *p=arg;
                printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
-                       "tuner=%d, std=%lld, status=%d\n", s,
+                       "tuner=%d, std=%Ld, status=%d\n", s,
                                p->index,p->name,p->type,p->audioset,
-                               p->tuner,p->std,
+                               p->tuner,
+                               (unsigned long long)p->std,
                                p->status);
                break;
        }
@@ -620,9 +612,10 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        {
                struct v4l2_output *p=arg;
                printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
-                       "modulator=%d, std=%lld\n",
+                       "modulator=%d, std=%Ld\n",
                                s,p->index,p->name,p->type,p->audioset,
-                               p->modulator,p->std);
+                               p->modulator,
+                               (unsigned long long)p->std);
                break;
        }
        case VIDIOC_QUERYCTRL:
@@ -665,7 +658,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        case VIDIOC_INT_G_VIDEO_ROUTING:
        {
                struct v4l2_routing  *p=arg;
-               printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+               printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
                break;
        }
        case VIDIOC_G_SLICED_VBI_CAP:
@@ -686,8 +679,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        case VIDIOC_ENUMSTD:
        {
                struct v4l2_standard *p=arg;
-               printk ("%s: index=%d, id=%lld, name=%s, fps=%d/%d, framelines=%d\n", s,
-                               p->index, p->id, p->name,
+               printk ("%s: index=%d, id=%Ld, name=%s, fps=%d/%d, "
+                       "framelines=%d\n", s, p->index,
+                               (unsigned long long)p->id, p->name,
                                p->frameperiod.numerator,
                                p->frameperiod.denominator,
                                p->framelines);
@@ -907,7 +901,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
        {
                v4l2_std_id *p=arg;
 
-               printk ("%s: value=%llu\n", s, *p);
+               printk ("%s: value=%Lu\n", s, (unsigned long long)*p);
                break;
        }
        }
index 87e937581d5aa679a837cb5ff0ec3deb1d68d070..d2ca0f08d0df635e4d2ae73669dfbec1f98e07d0 100644 (file)
@@ -1,15 +1,20 @@
 /*
  *
  * generic helper functions for video4linux capture buffers, to handle
- * memory management and PCI DMA.  Right now bttv + saa7134 use it.
+ * memory management and PCI DMA.
+ * Right now, bttv, saa7134, saa7146 and cx88 use it.
  *
  * The functions expect the hardware being able to scatter gatter
  * (i.e. the buffers are not linear in physical memory, but fragmented
  * into PAGE_SIZE chunks).  They also assume the driver does not need
- * to touch the video data (thus it is probably not useful for USB 1.1
- * as data often must be uncompressed by the drivers).
+ * to touch the video data.
+ *
+ * device specific map/unmap/sync stuff now are mapped as operations
+ * to allow its usage by USB and virtual devices.
  *
  * (c) 2001-2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ * (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * (c) 2006 Ted Walther and John Sokol
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -167,6 +172,9 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
                dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
                return -ENOMEM;
        }
+       dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+                               (unsigned long)dma->vmalloc,
+                               nr_pages << PAGE_SHIFT);
        memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
        dma->nr_pages = nr_pages;
        return 0;
@@ -186,8 +194,10 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
        return 0;
 }
 
-int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 {
+       void                   *dev=q->dev;
+
        MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
        BUG_ON(0 == dma->nr_pages);
 
@@ -197,7 +207,7 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma)
        }
        if (dma->vmalloc) {
                dma->sglist = videobuf_vmalloc_to_sg
-                       (dma->vmalloc,dma->nr_pages);
+                                               (dma->vmalloc,dma->nr_pages);
        }
        if (dma->bus_addr) {
                dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
@@ -212,13 +222,14 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma)
                dprintk(1,"scatterlist is NULL\n");
                return -ENOMEM;
        }
-
        if (!dma->bus_addr) {
-               dma->sglen = pci_map_sg(dev,dma->sglist,dma->nr_pages,
-                                       dma->direction);
+               if (q->ops->vb_map_sg) {
+                       dma->sglen = q->ops->vb_map_sg(dev,dma->sglist,
+                                       dma->nr_pages, dma->direction);
+               }
                if (0 == dma->sglen) {
                        printk(KERN_WARNING
-                              "%s: pci_map_sg failed\n",__FUNCTION__);
+                              "%s: videobuf_map_sg failed\n",__FUNCTION__);
                        kfree(dma->sglist);
                        dma->sglist = NULL;
                        dma->sglen = 0;
@@ -228,24 +239,31 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma)
        return 0;
 }
 
-int videobuf_dma_pci_sync(struct pci_dev *dev, struct videobuf_dmabuf *dma)
+int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 {
+       void                   *dev=q->dev;
+
        MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
        BUG_ON(!dma->sglen);
 
-       if (!dma->bus_addr)
-               pci_dma_sync_sg_for_cpu(dev,dma->sglist,dma->nr_pages,dma->direction);
+       if (!dma->bus_addr && q->ops->vb_dma_sync_sg)
+               q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages,
+                                                       dma->direction);
+
        return 0;
 }
 
-int videobuf_dma_pci_unmap(struct pci_dev *dev, struct videobuf_dmabuf *dma)
+int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 {
+       void                   *dev=q->dev;
+
        MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
        if (!dma->sglen)
                return 0;
 
-       if (!dma->bus_addr)
-               pci_unmap_sg(dev,dma->sglist,dma->nr_pages,dma->direction);
+       if (!dma->bus_addr && q->ops->vb_unmap_sg)
+                       q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages,
+                                                       dma->direction);
        kfree(dma->sglist);
        dma->sglist = NULL;
        dma->sglen = 0;
@@ -318,7 +336,7 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
 }
 
 int
-videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb,
+videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
                struct v4l2_framebuffer *fbuf)
 {
        int err,pages;
@@ -357,7 +375,7 @@ videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb,
        default:
                BUG();
        }
-       err = videobuf_dma_pci_map(pci,&vb->dma);
+       err = videobuf_dma_map(q,&vb->dma);
        if (0 != err)
                return err;
 
@@ -366,9 +384,41 @@ videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb,
 
 /* --------------------------------------------------------------------- */
 
+void videobuf_queue_pci(struct videobuf_queue* q)
+{
+       /* If not specified, defaults to PCI map sg */
+       if (!q->ops->vb_map_sg)
+               q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg;
+
+       if (!q->ops->vb_dma_sync_sg)
+               q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu;
+       if (!q->ops->vb_unmap_sg)
+               q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
+}
+
+int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+       struct videobuf_queue q;
+
+       q.dev=pci;
+       q.ops->vb_map_sg=(vb_map_sg_t *)pci_unmap_sg;
+
+       return (videobuf_dma_unmap(&q,dma));
+}
+
+int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+       struct videobuf_queue q;
+
+       q.dev=pci;
+       q.ops->vb_map_sg=(vb_map_sg_t *)pci_unmap_sg;
+
+       return (videobuf_dma_unmap(&q,dma));
+}
+
 void videobuf_queue_init(struct videobuf_queue* q,
                         struct videobuf_queue_ops *ops,
-                        struct pci_dev *pci,
+                        void *dev,
                         spinlock_t *irqlock,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
@@ -377,13 +427,15 @@ void videobuf_queue_init(struct videobuf_queue* q,
 {
        memset(q,0,sizeof(*q));
        q->irqlock = irqlock;
-       q->pci     = pci;
+       q->dev     = dev;
        q->type    = type;
        q->field   = field;
        q->msize   = msize;
        q->ops     = ops;
        q->priv_data = priv;
 
+       videobuf_queue_pci(q);
+
        mutex_init(&q->lock);
        INIT_LIST_HEAD(&q->stream);
 }
@@ -431,7 +483,8 @@ videobuf_queue_cancel(struct videobuf_queue *q)
        int i;
 
        /* remove queued buffers from list */
-       spin_lock_irqsave(q->irqlock,flags);
+       if (q->irqlock)
+               spin_lock_irqsave(q->irqlock,flags);
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
@@ -440,7 +493,8 @@ videobuf_queue_cancel(struct videobuf_queue *q)
                        q->bufs[i]->state = STATE_ERROR;
                }
        }
-       spin_unlock_irqrestore(q->irqlock,flags);
+       if (q->irqlock)
+               spin_unlock_irqrestore(q->irqlock,flags);
 
        /* free all buffers + clear queue */
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
@@ -534,19 +588,29 @@ videobuf_reqbufs(struct videobuf_queue *q,
        unsigned int size,count;
        int retval;
 
-       if (req->type != q->type)
+       if (req->type != q->type) {
+               dprintk(1,"reqbufs: queue type invalid\n");
                return -EINVAL;
-       if (req->count < 1)
+       }
+       if (req->count < 1) {
+               dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
                return -EINVAL;
+       }
        if (req->memory != V4L2_MEMORY_MMAP     &&
            req->memory != V4L2_MEMORY_USERPTR  &&
-           req->memory != V4L2_MEMORY_OVERLAY)
+           req->memory != V4L2_MEMORY_OVERLAY) {
+               dprintk(1,"reqbufs: memory type invalid\n");
                return -EINVAL;
+       }
 
-       if (q->streaming)
+       if (q->streaming) {
+               dprintk(1,"reqbufs: streaming already exists\n");
                return -EBUSY;
-       if (!list_empty(&q->stream))
+       }
+       if (!list_empty(&q->stream)) {
+               dprintk(1,"reqbufs: stream running\n");
                return -EBUSY;
+       }
 
        mutex_lock(&q->lock);
        count = req->count;
@@ -559,8 +623,10 @@ videobuf_reqbufs(struct videobuf_queue *q,
                count, size, (count*size)>>PAGE_SHIFT);
 
        retval = videobuf_mmap_setup(q,count,size,req->memory);
-       if (retval < 0)
+       if (retval < 0) {
+               dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
                goto done;
+       }
 
        req->count = count;
 
@@ -572,12 +638,18 @@ videobuf_reqbufs(struct videobuf_queue *q,
 int
 videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 {
-       if (unlikely(b->type != q->type))
+       if (unlikely(b->type != q->type)) {
+               dprintk(1,"querybuf: Wrong type.\n");
                return -EINVAL;
-       if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME))
+       }
+       if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
+               dprintk(1,"querybuf: index out of range.\n");
                return -EINVAL;
-       if (unlikely(NULL == q->bufs[b->index]))
+       }
+       if (unlikely(NULL == q->bufs[b->index])) {
+               dprintk(1,"querybuf: buffer is null.\n");
                return -EINVAL;
+       }
        videobuf_status(b,q->bufs[b->index],q->type);
        return 0;
 }
@@ -593,26 +665,40 @@ videobuf_qbuf(struct videobuf_queue *q,
 
        mutex_lock(&q->lock);
        retval = -EBUSY;
-       if (q->reading)
+       if (q->reading) {
+               dprintk(1,"qbuf: Reading running...\n");
                goto done;
+       }
        retval = -EINVAL;
-       if (b->type != q->type)
+       if (b->type != q->type) {
+               dprintk(1,"qbuf: Wrong type.\n");
                goto done;
-       if (b->index < 0 || b->index >= VIDEO_MAX_FRAME)
+       }
+       if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
+               dprintk(1,"qbuf: index out of range.\n");
                goto done;
+       }
        buf = q->bufs[b->index];
-       if (NULL == buf)
+       if (NULL == buf) {
+               dprintk(1,"qbuf: buffer is null.\n");
                goto done;
+       }
        MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
-       if (buf->memory != b->memory)
+       if (buf->memory != b->memory) {
+               dprintk(1,"qbuf: memory type is wrong.\n");
                goto done;
+       }
        if (buf->state == STATE_QUEUED ||
-           buf->state == STATE_ACTIVE)
+           buf->state == STATE_ACTIVE) {
+               dprintk(1,"qbuf: buffer is already queued or active.\n");
                goto done;
+       }
 
        if (b->flags & V4L2_BUF_FLAG_INPUT) {
-               if (b->input >= q->inputs)
+               if (b->input >= q->inputs) {
+                       dprintk(1,"qbuf: wrong input.\n");
                        goto done;
+               }
                buf->input = b->input;
        } else {
                buf->input = UNSET;
@@ -620,12 +706,16 @@ videobuf_qbuf(struct videobuf_queue *q,
 
        switch (b->memory) {
        case V4L2_MEMORY_MMAP:
-               if (0 == buf->baddr)
+               if (0 == buf->baddr) {
+                       dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
                        goto done;
+               }
                break;
        case V4L2_MEMORY_USERPTR:
-               if (b->length < buf->bsize)
+               if (b->length < buf->bsize) {
+                       dprintk(1,"qbuf: buffer length is not enough\n");
                        goto done;
+               }
                if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
                        q->ops->buf_release(q,buf);
                buf->baddr = b->m.userptr;
@@ -634,20 +724,27 @@ videobuf_qbuf(struct videobuf_queue *q,
                buf->boff = b->m.offset;
                break;
        default:
+               dprintk(1,"qbuf: wrong memory type\n");
                goto done;
        }
 
+       dprintk(1,"qbuf: requesting next field\n");
        field = videobuf_next_field(q);
        retval = q->ops->buf_prepare(q,buf,field);
-       if (0 != retval)
+       if (0 != retval) {
+               dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
                goto done;
+       }
 
        list_add_tail(&buf->stream,&q->stream);
        if (q->streaming) {
-               spin_lock_irqsave(q->irqlock,flags);
+               if (q->irqlock)
+                       spin_lock_irqsave(q->irqlock,flags);
                q->ops->buf_queue(q,buf);
-               spin_unlock_irqrestore(q->irqlock,flags);
+               if (q->irqlock)
+                       spin_unlock_irqrestore(q->irqlock,flags);
        }
+       dprintk(1,"qbuf: succeded\n");
        retval = 0;
 
  done:
@@ -664,26 +761,39 @@ videobuf_dqbuf(struct videobuf_queue *q,
 
        mutex_lock(&q->lock);
        retval = -EBUSY;
-       if (q->reading)
+       if (q->reading) {
+               dprintk(1,"dqbuf: Reading running...\n");
                goto done;
+       }
        retval = -EINVAL;
-       if (b->type != q->type)
+       if (b->type != q->type) {
+               dprintk(1,"dqbuf: Wrong type.\n");
                goto done;
-       if (list_empty(&q->stream))
+       }
+       if (list_empty(&q->stream)) {
+               dprintk(1,"dqbuf: stream running\n");
                goto done;
+       }
        buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
        retval = videobuf_waiton(buf, nonblocking, 1);
-       if (retval < 0)
+       if (retval < 0) {
+               dprintk(1,"dqbuf: waiton returned %d\n",retval);
                goto done;
+       }
        switch (buf->state) {
        case STATE_ERROR:
+               dprintk(1,"dqbuf: state is error\n");
                retval = -EIO;
-               /* fall through */
+               videobuf_dma_sync(q,&buf->dma);
+               buf->state = STATE_IDLE;
+               break;
        case STATE_DONE:
-               videobuf_dma_pci_sync(q->pci,&buf->dma);
+               dprintk(1,"dqbuf: state is done\n");
+               videobuf_dma_sync(q,&buf->dma);
                buf->state = STATE_IDLE;
                break;
        default:
+               dprintk(1,"dqbuf: state invalid\n");
                retval = -EINVAL;
                goto done;
        }
@@ -711,13 +821,15 @@ int videobuf_streamon(struct videobuf_queue *q)
        if (q->streaming)
                goto done;
        q->streaming = 1;
-       spin_lock_irqsave(q->irqlock,flags);
+       if (q->irqlock)
+               spin_lock_irqsave(q->irqlock,flags);
        list_for_each(list,&q->stream) {
                buf = list_entry(list, struct videobuf_buffer, stream);
                if (buf->state == STATE_PREPARED)
                        q->ops->buf_queue(q,buf);
        }
-       spin_unlock_irqrestore(q->irqlock,flags);
+       if (q->irqlock)
+               spin_unlock_irqrestore(q->irqlock,flags);
 
  done:
        mutex_unlock(&q->lock);
@@ -762,12 +874,14 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
                goto done;
 
        /* start capture & wait */
-       spin_lock_irqsave(q->irqlock,flags);
+       if (q->irqlock)
+               spin_lock_irqsave(q->irqlock,flags);
        q->ops->buf_queue(q,q->read_buf);
-       spin_unlock_irqrestore(q->irqlock,flags);
+       if (q->irqlock)
+               spin_unlock_irqrestore(q->irqlock,flags);
        retval = videobuf_waiton(q->read_buf,0,0);
        if (0 == retval) {
-               videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
+               videobuf_dma_sync(q,&q->read_buf->dma);
                if (STATE_ERROR == q->read_buf->state)
                        retval = -EIO;
                else
@@ -809,6 +923,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                /* need to capture a new frame */
                retval = -ENOMEM;
                q->read_buf = videobuf_alloc(q->msize);
+               dprintk(1,"video alloc=0x%08x\n",(unsigned int) q->read_buf);
                if (NULL == q->read_buf)
                        goto done;
                q->read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -820,9 +935,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                        q->read_buf = NULL;
                        goto done;
                }
-               spin_lock_irqsave(q->irqlock,flags);
+               if (q->irqlock)
+                       spin_lock_irqsave(q->irqlock,flags);
                q->ops->buf_queue(q,q->read_buf);
-               spin_unlock_irqrestore(q->irqlock,flags);
+               if (q->irqlock)
+                       spin_unlock_irqrestore(q->irqlock,flags);
                q->read_off = 0;
        }
 
@@ -830,7 +947,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        retval = videobuf_waiton(q->read_buf, nonblocking, 1);
        if (0 != retval)
                goto done;
-       videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
+       videobuf_dma_sync(q,&q->read_buf->dma);
 
        if (STATE_ERROR == q->read_buf->state) {
                /* catch I/O errors */
@@ -887,10 +1004,12 @@ int videobuf_read_start(struct videobuf_queue *q)
                        return err;
                list_add_tail(&q->bufs[i]->stream, &q->stream);
        }
-       spin_lock_irqsave(q->irqlock,flags);
+       if (q->irqlock)
+               spin_lock_irqsave(q->irqlock,flags);
        for (i = 0; i < count; i++)
                q->ops->buf_queue(q,q->bufs[i]);
-       spin_unlock_irqrestore(q->irqlock,flags);
+       if (q->irqlock)
+               spin_unlock_irqrestore(q->irqlock,flags);
        q->reading = 1;
        return 0;
 }
@@ -985,9 +1104,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                if (q->read_off == q->read_buf->size) {
                        list_add_tail(&q->read_buf->stream,
                                      &q->stream);
-                       spin_lock_irqsave(q->irqlock,flags);
+                       if (q->irqlock)
+                               spin_lock_irqsave(q->irqlock,flags);
                        q->ops->buf_queue(q,q->read_buf);
-                       spin_unlock_irqrestore(q->irqlock,flags);
+                       if (q->irqlock)
+                               spin_unlock_irqrestore(q->irqlock,flags);
                        q->read_buf = NULL;
                }
                if (retval < 0)
@@ -1249,11 +1370,14 @@ EXPORT_SYMBOL_GPL(videobuf_dma_init);
 EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
 EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
 EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-EXPORT_SYMBOL_GPL(videobuf_dma_pci_map);
-EXPORT_SYMBOL_GPL(videobuf_dma_pci_sync);
-EXPORT_SYMBOL_GPL(videobuf_dma_pci_unmap);
+EXPORT_SYMBOL_GPL(videobuf_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_dma_sync);
+EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
 EXPORT_SYMBOL_GPL(videobuf_dma_free);
 
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
+
 EXPORT_SYMBOL_GPL(videobuf_alloc);
 EXPORT_SYMBOL_GPL(videobuf_waiton);
 EXPORT_SYMBOL_GPL(videobuf_iolock);
index b1239ac7f371a734ad393c15cc74805186f8e9c8..8c233720b6a50d3a56508ccdfb1c31ff5bcd941a 100644 (file)
@@ -57,7 +57,7 @@
    therfor they may not be initialized.
 
    The other fuctions are just for convenience, as they are for sure used by
-   most/all of the codecs. The last ones may be ommited, too. 
+   most/all of the codecs. The last ones may be ommited, too.
 
    See the structure declaration below for more information and which data has
    to be set up for the master and the slave.
 /* ========================================== */
 
 /*
-   ==== master setup ==== 
+   ==== master setup ====
    name -> name of the device structure for reference and debugging
    master_data ->  data ref. for the master (e.g. the zr36055,57,67)
    readreg -> ref. to read-fn from register (setup by master, used by slave)
    writereg -> ref. to write-fn to register (setup by master, used by slave)
-               this two functions do the lowlevel I/O job
+              this two functions do the lowlevel I/O job
 
-   ==== slave functionality setup ==== 
-   slave_data -> data ref. for the slave (e.g. the zr36050,60) 
+   ==== slave functionality setup ====
+   slave_data -> data ref. for the slave (e.g. the zr36050,60)
    check -> fn-ref. checks availability of an device, returns -EIO on failure or
-            the type on success
-            this makes espcecially sense if a driver module supports more than
-            one codec which may be quite similar to access, nevertheless it
-            is good for a first functionality check 
+           the type on success
+           this makes espcecially sense if a driver module supports more than
+           one codec which may be quite similar to access, nevertheless it
+           is good for a first functionality check
 
-   -- main functions you always need for compression/decompression -- 
+   -- main functions you always need for compression/decompression --
 
    set_mode -> this fn-ref. resets the entire codec, and sets up the mode
-               with the last defined norm/size (or device default if not
-               available) - it returns 0 if the mode is possible 
+              with the last defined norm/size (or device default if not
+              available) - it returns 0 if the mode is possible
    set_size -> this fn-ref. sets the norm and image size for
-               compression/decompression (returns 0 on success) 
-               the norm param is defined in videodev.h (VIDEO_MODE_*) 
+              compression/decompression (returns 0 on success)
+              the norm param is defined in videodev.h (VIDEO_MODE_*)
 
    additional setup may be available, too - but the codec should work with
-   some default values even without this 
+   some default values even without this
 
-   set_data -> sets device-specific data (tables, quality etc.) 
-   get_data -> query device-specific data (tables, quality etc.) 
+   set_data -> sets device-specific data (tables, quality etc.)
+   get_data -> query device-specific data (tables, quality etc.)
 
-   if the device delivers interrupts, they may be setup/handled here 
-   setup_interrupt -> codec irq setup (not needed for 36050/60) 
-   handle_interrupt -> codec irq handling (not needed for 36050/60) 
+   if the device delivers interrupts, they may be setup/handled here
+   setup_interrupt -> codec irq setup (not needed for 36050/60)
+   handle_interrupt -> codec irq handling (not needed for 36050/60)
 
-   if the device delivers pictures, they may be handled here 
-   put_image -> puts image data to the codec (not needed for 36050/60) 
-   get_image -> gets image data from the codec (not needed for 36050/60) 
-                the calls include frame numbers and flags (even/odd/...) 
-                if needed and a flag which allows blocking until its ready 
+   if the device delivers pictures, they may be handled here
+   put_image -> puts image data to the codec (not needed for 36050/60)
+   get_image -> gets image data from the codec (not needed for 36050/60)
+               the calls include frame numbers and flags (even/odd/...)
+               if needed and a flag which allows blocking until its ready
 */
 \f
 /* ============== */
 /* user interface */
 /* ============== */
 
-/* 
+/*
    Currently there is only a information display planned, as the layer
    is not visible for the user space at all.
 
index 0229819d0aaca75d4f807cdffb40c4f275adc5a6..a8c101494cf575f947fd804eccdde524140bb1ec 100644 (file)
@@ -1555,12 +1555,12 @@ static void vino_update_line_size(struct vino_channel_settings *vcs)
        unsigned int w = vcs->clipping.right - vcs->clipping.left;
        unsigned int d = vcs->decimation;
        unsigned int bpp = vino_data_formats[vcs->data_format].bpp;
-        unsigned int lsize;
+       unsigned int lsize;
 
        dprintk("update_line_size(): before: w = %d, d = %d, "
                "line_size = %d\n", w, d, vcs->line_size);
 
-        /* line size must be multiple of 8 bytes */
+       /* line size must be multiple of 8 bytes */
        lsize = (bpp * (w / d)) & ~7;
        w = (lsize / bpp) * d;
 
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
new file mode 100644 (file)
index 0000000..5e81340
--- /dev/null
@@ -0,0 +1,1454 @@
+/*
+ * Virtual Video driver - This code emulates a real video device with v4l2 api
+ *
+ * Copyright (c) 2006 by:
+ *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ *      Ted Walther <ted--a.t--enumera.com>
+ *      John Sokol <sokol--a.t--videotechnology.com>
+ *      http://v4l.videotechnology.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the BSD Licence, GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/interrupt.h>
+#include <media/video-buf.h>
+#include <media/v4l2-common.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+
+/* Wake up at about 30 fps */
+#define WAKE_NUMERATOR 30
+#define WAKE_DENOMINATOR 1001
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+
+/* These timers are for 1 fps - used only for testing */
+//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */
+//#define BUFFER_TIMEOUT     msecs_to_jiffies(5000)  /* 5 seconds */
+
+#include "font.h"
+
+#ifndef kzalloc
+#define kzalloc(size, flags)                            \
+({                                                      \
+       void *__ret = kmalloc(size, flags);             \
+       if (__ret)                                      \
+               memset(__ret, 0, size);                 \
+       __ret;                                          \
+})
+#endif
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define VIVI_MAJOR_VERSION 0
+#define VIVI_MINOR_VERSION 4
+#define VIVI_RELEASE 0
+#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+
+static int video_nr = -1;        /* /dev/videoN, -1 for autodetect */
+module_param(video_nr, int, 0);
+
+static int debug = 0;
+module_param(debug, int, 0);
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
+/* supported controls */
+static struct v4l2_queryctrl vivi_qctrl[] = {
+       {
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .name          = "Volume",
+               .minimum       = 0,
+               .maximum       = 65535,
+               .step          = 65535/100,
+               .default_value = 65535,
+               .flags         = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+       },{
+               .id            = V4L2_CID_BRIGHTNESS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 127,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_CONTRAST,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 0x1,
+               .default_value = 0x10,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_SATURATION,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 0x1,
+               .default_value = 127,
+               .flags         = 0,
+       }, {
+               .id            = V4L2_CID_HUE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Hue",
+               .minimum       = -128,
+               .maximum       = 127,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = 0,
+       }
+};
+
+static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
+
+#define dprintk(level,fmt, arg...)                          \
+       do {                                                 \
+               if (debug >= (level))                        \
+                       printk(KERN_DEBUG "vivi: " fmt , ## arg);    \
+       } while (0)
+
+/* ------------------------------------------------------------------
+       Basic structures
+   ------------------------------------------------------------------*/
+
+struct vivi_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+};
+
+static struct vivi_fmt format = {
+       .name     = "4:2:2, packed, YUYV",
+       .fourcc   = V4L2_PIX_FMT_YUYV,
+       .depth    = 16,
+};
+
+struct sg_to_addr {
+       int pos;
+       struct scatterlist *sg;
+};
+
+/* buffer for one video frame */
+struct vivi_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+
+       struct vivi_fmt        *fmt;
+
+       struct sg_to_addr      *to_addr;
+};
+
+struct vivi_dmaqueue {
+       struct list_head       active;
+       struct list_head       queued;
+       struct timer_list      timeout;
+
+       /* thread for generating video stream*/
+       struct task_struct         *kthread;
+       wait_queue_head_t          wq;
+       /* Counters to control fps rate */
+       int                        frame;
+       int                        ini_jiffies;
+};
+
+static LIST_HEAD(vivi_devlist);
+
+struct vivi_dev {
+       struct list_head           vivi_devlist;
+
+       struct semaphore           lock;
+
+       int                        users;
+
+       /* various device info */
+       unsigned int               resources;
+       struct video_device        video_dev;
+
+       struct vivi_dmaqueue       vidq;
+
+       /* Several counters */
+       int                        h,m,s,us,jiffies;
+       char                       timestr[13];
+};
+
+struct vivi_fh {
+       struct vivi_dev            *dev;
+
+       /* video capture */
+       struct vivi_fmt            *fmt;
+       unsigned int               width,height;
+       struct videobuf_queue      vb_vidq;
+
+       enum v4l2_buf_type         type;
+};
+
+/* ------------------------------------------------------------------
+       DMA and thread functions
+   ------------------------------------------------------------------*/
+
+/* Bars and Colors should match positions */
+
+enum colors {
+       WHITE,
+       AMBAR,
+       CYAN,
+       GREEN,
+       MAGENTA,
+       RED,
+       BLUE
+};
+
+static u8 bars[8][3] = {
+       /* R   G   B */
+       {204,204,204},  /* white */
+       {208,208,  0},  /* ambar */
+       {  0,206,206},  /* cyan */
+       {  0,239,  0},  /* green */
+       {239,  0,239},  /* magenta */
+       {205,  0,  0},  /* red */
+       {  0,  0,255},  /* blue */
+       {  0,  0,  0}
+};
+
+#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b  + 32768)>>16)+16)
+/* RGB to  V(Cr) Color transform */
+#define TO_V(r,g,b) (((28784*r -24103*g -4681*b  + 32768)>>16)+128)
+/* RGB to  U(Cb) Color transform */
+#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128)
+
+#define TSTAMP_MIN_Y 24
+#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
+#define TSTAMP_MIN_X 64
+
+void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
+{
+       int i, pos=0;
+
+       for (i=0;i<vb->dma.nr_pages;i++) {
+               to_addr[i].sg=&vb->dma.sglist[i];
+               to_addr[i].pos=pos;
+               pos += vb->dma.sglist[i].length;
+       }
+}
+
+inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
+{
+       int p1=0,p2=pages-1,p3=pages/2;
+
+       /* Sanity test */
+       BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
+
+       while (p1+1<p2) {
+               if (pos < to_addr[p3].pos) {
+                       p2=p3;
+               } else {
+                       p1=p3;
+               }
+               p3=(p1+p2)/2;
+       }
+       if (pos >= to_addr[p2].pos)
+               p1=p2;
+
+       return (p1);
+}
+
+void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
+                                       int hmax, int line, char *timestr)
+{
+       int  w,i,j,pos=inipos,pgpos,oldpg,y;
+       char *p,*s,*basep;
+       struct page *pg;
+       u8   chr,r,g,b,color;
+
+       /* Get first addr pointed to pixel position */
+       oldpg=get_addr_pos(pos,pages,to_addr);
+       pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT);
+       basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
+
+       /* We will just duplicate the second pixel at the packet */
+       wmax/=2;
+
+       /* Generate a standard color bar pattern */
+       for (w=0;w<wmax;w++) {
+               r=bars[w*7/wmax][0];
+               g=bars[w*7/wmax][1];
+               b=bars[w*7/wmax][2];
+
+               for (color=0;color<4;color++) {
+                       pgpos=get_addr_pos(pos,pages,to_addr);
+                       if (pgpos!=oldpg) {
+                               pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT);
+                               kunmap_atomic(basep, KM_BOUNCE_READ);
+                               basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
+                               oldpg=pgpos;
+                       }
+                       p=basep+pos-to_addr[pgpos].pos;
+
+                       switch (color) {
+                               case 0:
+                               case 2:
+                                       *p=TO_Y(r,g,b);         /* Luminance */
+                                       break;
+                               case 1:
+                                       *p=TO_U(r,g,b);         /* Cb */
+                                       break;
+                               case 3:
+                                       *p=TO_V(r,g,b);         /* Cr */
+                                       break;
+                       }
+                       pos++;
+               }
+       }
+
+       /* Checks if it is possible to show timestamp */
+       if (TSTAMP_MAX_Y>=hmax)
+               goto end;
+       if (TSTAMP_MIN_X+strlen(timestr)>=wmax)
+               goto end;
+
+       /* Print stream time */
+       if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) {
+               j=TSTAMP_MIN_X;
+               for (s=timestr;*s;s++) {
+                       chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
+                       for (i=0;i<7;i++) {
+                               if (chr&1<<(7-i)) { /* Font color*/
+                                       r=bars[BLUE][0];
+                                       g=bars[BLUE][1];
+                                       b=bars[BLUE][2];
+                                       r=g=b=0;
+                                       g=198;
+                               } else { /* Background color */
+                                       r=bars[WHITE][0];
+                                       g=bars[WHITE][1];
+                                       b=bars[WHITE][2];
+                                       r=g=b=0;
+                               }
+
+                               pos=inipos+j*2;
+                               for (color=0;color<4;color++) {
+                                       pgpos=get_addr_pos(pos,pages,to_addr);
+                                       if (pgpos!=oldpg) {
+                                               pg=pfn_to_page(to_addr[pgpos].
+                                                               sg->dma_address
+                                                               >> PAGE_SHIFT);
+                                               kunmap_atomic(basep,
+                                                               KM_BOUNCE_READ);
+                                               basep= kmap_atomic(pg,
+                                                       KM_BOUNCE_READ)+
+                                                       to_addr[pgpos].sg->offset;
+                                               oldpg=pgpos;
+                                       }
+                                       p=basep+pos-to_addr[pgpos].pos;
+
+                                       y=TO_Y(r,g,b);
+
+                                       switch (color) {
+                                               case 0:
+                                               case 2:
+                                                       *p=TO_Y(r,g,b);         /* Luminance */
+                                                       break;
+                                               case 1:
+                                                       *p=TO_U(r,g,b);         /* Cb */
+                                                       break;
+                                               case 3:
+                                                       *p=TO_V(r,g,b);         /* Cr */
+                                                       break;
+                                       }
+                                       pos++;
+                               }
+                               j++;
+                       }
+               }
+       }
+
+
+end:
+       kunmap_atomic(basep, KM_BOUNCE_READ);
+}
+static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
+{
+       int h,pos=0;
+       int hmax  = buf->vb.height;
+       int wmax  = buf->vb.width;
+       struct videobuf_buffer *vb=&buf->vb;
+       struct sg_to_addr *to_addr=buf->to_addr;
+       struct timeval ts;
+
+       /* Test if DMA mapping is ready */
+       if (!vb->dma.sglist[0].dma_address)
+               return;
+
+       prep_to_addr(to_addr,vb);
+
+       /* Check if there is enough memory */
+       BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
+
+       for (h=0;h<hmax;h++) {
+               gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
+               pos += wmax*2;
+       }
+
+       /* Updates stream time */
+
+       dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
+       dev->jiffies=jiffies;
+       if (dev->us>=1000000) {
+               dev->us-=1000000;
+               dev->s++;
+               if (dev->s>=60) {
+                       dev->s-=60;
+                       dev->m++;
+                       if (dev->m>60) {
+                               dev->m-=60;
+                               dev->h++;
+                               if (dev->h>24)
+                                       dev->h-=24;
+                       }
+               }
+       }
+       sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
+                       dev->h,dev->m,dev->s,(dev->us+500)/1000);
+
+       dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
+                       (unsigned long)buf->vb.dma.vmalloc,pos);
+
+       /* Advice that buffer was filled */
+       buf->vb.state = STATE_DONE;
+       buf->vb.field_count++;
+       do_gettimeofday(&ts);
+       buf->vb.ts = ts;
+
+       list_del(&buf->vb.queue);
+       wake_up(&buf->vb.done);
+}
+
+static int restart_video_queue(struct vivi_dmaqueue *dma_q);
+
+static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
+{
+       struct vivi_buffer    *buf;
+       struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq);
+
+       int bc;
+
+       /* Announces videobuf that all went ok */
+       for (bc = 0;; bc++) {
+               if (list_empty(&dma_q->active)) {
+                       dprintk(1,"No active queue to serve\n");
+                       break;
+               }
+
+               buf = list_entry(dma_q->active.next,
+                                struct vivi_buffer, vb.queue);
+
+               /* Nobody is waiting something to be done, just return */
+               if (!waitqueue_active(&buf->vb.done)) {
+                       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+                       return;
+               }
+
+               do_gettimeofday(&buf->vb.ts);
+               dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i);
+
+               /* Fill buffer */
+               vivi_fillbuff(dev,buf);
+       }
+       if (list_empty(&dma_q->active)) {
+               del_timer(&dma_q->timeout);
+       } else {
+               mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+       }
+       if (bc != 1)
+               dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+}
+
+void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+{
+       int timeout;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
+
+       add_wait_queue(&dma_q->wq, &wait);
+       if (!kthread_should_stop()) {
+               dma_q->frame++;
+
+               /* Calculate time to wake up */
+               timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
+
+               if (timeout <= 0) {
+                       int old=dma_q->frame;
+                       dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1;
+
+                       timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
+
+                       dprintk(1,"underrun, losed %d frames. "
+                                 "Now, frame is %d. Waking on %d jiffies\n",
+                                       dma_q->frame-old,dma_q->frame,timeout);
+               } else
+                       dprintk(1,"will sleep for %i jiffies\n",timeout);
+
+               vivi_thread_tick(dma_q);
+
+               schedule_timeout_interruptible (timeout);
+       }
+
+       remove_wait_queue(&dma_q->wq, &wait);
+       try_to_freeze();
+}
+
+int vivi_thread(void *data)
+{
+       struct vivi_dmaqueue  *dma_q=data;
+
+       dprintk(1,"thread started\n");
+
+       for (;;) {
+               vivi_sleep(dma_q);
+
+               if (kthread_should_stop())
+                       break;
+       }
+       dprintk(1, "thread: exit\n");
+       return 0;
+}
+
+int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+{
+       dma_q->frame=0;
+       dma_q->ini_jiffies=jiffies;
+
+       dprintk(1,"%s\n",__FUNCTION__);
+       init_waitqueue_head(&dma_q->wq);
+
+       dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
+
+       if (dma_q->kthread == NULL) {
+               printk(KERN_ERR "vivi: kernel_thread() failed\n");
+               return -EINVAL;
+       }
+       dprintk(1,"returning from %s\n",__FUNCTION__);
+       return 0;
+}
+
+void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+{
+       dprintk(1,"%s\n",__FUNCTION__);
+       /* shutdown control thread */
+       if (dma_q->kthread) {
+               kthread_stop(dma_q->kthread);
+               dma_q->kthread=NULL;
+       }
+}
+
+static int restart_video_queue(struct vivi_dmaqueue *dma_q)
+{
+       struct vivi_buffer *buf, *prev;
+       struct list_head *item;
+
+       dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
+
+       if (!list_empty(&dma_q->active)) {
+               buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue);
+               dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+                       buf, buf->vb.i);
+
+               dprintk(1,"Restarting video dma\n");
+               vivi_stop_thread(dma_q);
+//             vivi_start_thread(dma_q);
+
+               /* cancel all outstanding capture / vbi requests */
+               list_for_each(item,&dma_q->active) {
+                       buf = list_entry(item, struct vivi_buffer, vb.queue);
+
+                       list_del(&buf->vb.queue);
+                       buf->vb.state = STATE_ERROR;
+                       wake_up(&buf->vb.done);
+               }
+               mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
+               return 0;
+       }
+
+       prev = NULL;
+       for (;;) {
+               if (list_empty(&dma_q->queued))
+                       return 0;
+               buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue);
+               if (NULL == prev) {
+                       list_del(&buf->vb.queue);
+                       list_add_tail(&buf->vb.queue,&dma_q->active);
+
+                       dprintk(1,"Restarting video dma\n");
+                       vivi_stop_thread(dma_q);
+                       vivi_start_thread(dma_q);
+
+                       buf->vb.state = STATE_ACTIVE;
+                       mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+                       dprintk(2,"[%p/%d] restart_queue - first active\n",
+                               buf,buf->vb.i);
+
+               } else if (prev->vb.width  == buf->vb.width  &&
+                          prev->vb.height == buf->vb.height &&
+                          prev->fmt       == buf->fmt) {
+                       list_del(&buf->vb.queue);
+                       list_add_tail(&buf->vb.queue,&dma_q->active);
+                       buf->vb.state = STATE_ACTIVE;
+                       dprintk(2,"[%p/%d] restart_queue - move to active\n",
+                               buf,buf->vb.i);
+               } else {
+                       return 0;
+               }
+               prev = buf;
+       }
+}
+
+static void vivi_vid_timeout(unsigned long data)
+{
+       struct vivi_dev      *dev  = (struct vivi_dev*)data;
+       struct vivi_dmaqueue *vidq = &dev->vidq;
+       struct vivi_buffer   *buf;
+
+       while (!list_empty(&vidq->active)) {
+               buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue);
+               list_del(&buf->vb.queue);
+               buf->vb.state = STATE_ERROR;
+               wake_up(&buf->vb.done);
+               printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
+       }
+
+       restart_video_queue(vidq);
+}
+
+/* ------------------------------------------------------------------
+       Videobuf operations
+   ------------------------------------------------------------------*/
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+       struct vivi_fh *fh = vq->priv_data;
+
+       *size = fh->width*fh->height*2;
+
+       if (0 == *count)
+               *count = 32;
+       while (*size * *count > vid_limit * 1024 * 1024)
+               (*count)--;
+       return 0;
+}
+
+void
+free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+{
+       dprintk(1,"%s\n",__FUNCTION__);
+
+       if (in_interrupt())
+               BUG();
+
+       /*FIXME: Maybe a spinlock is required here */
+       kfree(buf->to_addr);
+       buf->to_addr=NULL;
+
+       videobuf_waiton(&buf->vb,0,0);
+       videobuf_dma_unmap(vq, &buf->vb.dma);
+       videobuf_dma_free(&buf->vb.dma);
+       buf->vb.state = STATE_NEEDS_INIT;
+}
+
+#define norm_maxw() 1024
+#define norm_maxh() 768
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+                                               enum v4l2_field field)
+{
+       struct vivi_fh     *fh  = vq->priv_data;
+       struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
+       int rc, init_buffer = 0;
+
+//     dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+
+       BUG_ON(NULL == fh->fmt);
+       if (fh->width  < 48 || fh->width  > norm_maxw() ||
+           fh->height < 32 || fh->height > norm_maxh())
+               return -EINVAL;
+       buf->vb.size = fh->width*fh->height*2;
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       if (buf->fmt       != fh->fmt    ||
+           buf->vb.width  != fh->width  ||
+           buf->vb.height != fh->height ||
+       buf->vb.field  != field) {
+               buf->fmt       = fh->fmt;
+               buf->vb.width  = fh->width;
+               buf->vb.height = fh->height;
+               buf->vb.field  = field;
+               init_buffer = 1;
+       }
+
+       if (STATE_NEEDS_INIT == buf->vb.state) {
+               if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
+                       goto fail;
+       }
+
+       buf->vb.state = STATE_PREPARED;
+
+       if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
+               rc=-ENOMEM;
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       free_buffer(vq,buf);
+       return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct vivi_buffer    *buf     = container_of(vb,struct vivi_buffer,vb);
+       struct vivi_fh        *fh      = vq->priv_data;
+       struct vivi_dev       *dev     = fh->dev;
+       struct vivi_dmaqueue  *vidq    = &dev->vidq;
+       struct vivi_buffer    *prev;
+
+       if (!list_empty(&vidq->queued)) {
+               dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue);
+               list_add_tail(&buf->vb.queue,&vidq->queued);
+               buf->vb.state = STATE_QUEUED;
+               dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
+                       buf, buf->vb.i);
+       } else if (list_empty(&vidq->active)) {
+               list_add_tail(&buf->vb.queue,&vidq->active);
+
+               buf->vb.state = STATE_ACTIVE;
+               mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+               dprintk(2,"[%p/%d] buffer_queue - first active\n",
+                       buf, buf->vb.i);
+
+               vivi_start_thread(vidq);
+       } else {
+               prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue);
+               if (prev->vb.width  == buf->vb.width  &&
+                   prev->vb.height == buf->vb.height &&
+                   prev->fmt       == buf->fmt) {
+                       list_add_tail(&buf->vb.queue,&vidq->active);
+                       buf->vb.state = STATE_ACTIVE;
+                       dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+                               buf, buf->vb.i);
+
+               } else {
+                       list_add_tail(&buf->vb.queue,&vidq->queued);
+                       buf->vb.state = STATE_QUEUED;
+                       dprintk(2,"[%p/%d] buffer_queue - first queued\n",
+                               buf, buf->vb.i);
+               }
+       }
+}
+
+static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct vivi_buffer   *buf  = container_of(vb,struct vivi_buffer,vb);
+       struct vivi_fh       *fh   = vq->priv_data;
+       struct vivi_dev      *dev  = (struct vivi_dev*)fh->dev;
+       struct vivi_dmaqueue *vidq = &dev->vidq;
+
+       dprintk(1,"%s\n",__FUNCTION__);
+
+       vivi_stop_thread(vidq);
+
+       free_buffer(vq,buf);
+}
+
+int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
+          int direction)
+{
+       int i;
+
+       dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
+       BUG_ON(direction == DMA_NONE);
+
+       for (i = 0; i < nents; i++ ) {
+               BUG_ON(!sg[i].page);
+
+               sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+       }
+
+       return nents;
+}
+
+int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
+                                       int direction)
+{
+       dprintk(1,"%s\n",__FUNCTION__);
+       return 0;
+}
+
+int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages,
+                                       int direction)
+{
+//     dprintk(1,"%s\n",__FUNCTION__);
+
+//     flush_write_buffers();
+       return 0;
+}
+
+static struct videobuf_queue_ops vivi_video_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+
+       /* Non-pci handling routines */
+       .vb_map_sg      = vivi_map_sg,
+       .vb_dma_sync_sg = vivi_dma_sync_sg,
+       .vb_unmap_sg    = vivi_unmap_sg,
+};
+
+/* ------------------------------------------------------------------
+       IOCTL handling
+   ------------------------------------------------------------------*/
+
+static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+                       struct v4l2_format *f)
+{
+       struct vivi_fmt *fmt;
+       enum v4l2_field field;
+       unsigned int maxw, maxh;
+
+       if (format.fourcc != f->fmt.pix.pixelformat) {
+               dprintk(1,"Fourcc format invalid.\n");
+               return -EINVAL;
+       }
+       fmt=&format;
+
+       field = f->fmt.pix.field;
+
+       if (field == V4L2_FIELD_ANY) {
+//             field=V4L2_FIELD_INTERLACED;
+               field=V4L2_FIELD_SEQ_TB;
+       } else if (V4L2_FIELD_INTERLACED != field) {
+               dprintk(1,"Field type invalid.\n");
+               return -EINVAL;
+       }
+
+       maxw  = norm_maxw();
+       maxh  = norm_maxh();
+
+       f->fmt.pix.field = field;
+       if (f->fmt.pix.height < 32)
+               f->fmt.pix.height = 32;
+       if (f->fmt.pix.height > maxh)
+               f->fmt.pix.height = maxh;
+       if (f->fmt.pix.width < 48)
+               f->fmt.pix.width = 48;
+       if (f->fmt.pix.width > maxw)
+               f->fmt.pix.width = maxw;
+       f->fmt.pix.width &= ~0x03;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+       /* is it free? */
+       down(&dev->lock);
+       if (dev->resources) {
+               /* no, someone else uses it */
+               up(&dev->lock);
+               return 0;
+       }
+       /* it's free, grab it */
+       dev->resources =1;
+       dprintk(1,"res: get\n");
+       up(&dev->lock);
+       return 1;
+}
+
+static inline int res_locked(struct vivi_dev *dev)
+{
+       return (dev->resources);
+}
+
+static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+       down(&dev->lock);
+       dev->resources = 0;
+       dprintk(1,"res: put\n");
+       up(&dev->lock);
+}
+
+static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+{
+       struct vivi_fh  *fh     = file->private_data;
+       struct vivi_dev *dev    = fh->dev;
+       int ret=0;
+
+       if (debug) {
+               if (_IOC_DIR(cmd) & _IOC_WRITE)
+                       v4l_printk_ioctl_arg("vivi(w)",cmd, arg);
+               else if (!_IOC_DIR(cmd) & _IOC_READ) {
+                       v4l_print_ioctl("vivi", cmd);
+               }
+       }
+
+       switch(cmd) {
+       /* --- capabilities ------------------------------------------ */
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+
+               memset(cap, 0, sizeof(*cap));
+
+               strcpy(cap->driver, "vivi");
+               strcpy(cap->card, "vivi");
+               cap->version = VIVI_VERSION;
+               cap->capabilities =
+                                       V4L2_CAP_VIDEO_CAPTURE |
+                                       V4L2_CAP_STREAMING     |
+                                       V4L2_CAP_READWRITE;
+               break;
+       }
+       /* --- capture ioctls ---------------------------------------- */
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *f = arg;
+               enum v4l2_buf_type type;
+               unsigned int index;
+
+               index = f->index;
+               type  = f->type;
+
+               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+
+               switch (type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       if (index > 0){
+                               ret=-EINVAL;
+                               break;
+                       }
+                       memset(f,0,sizeof(*f));
+
+                       f->index = index;
+                       f->type  = type;
+                       strlcpy(f->description,format.name,sizeof(f->description));
+                       f->pixelformat = format.fourcc;
+                       break;
+               default:
+                       ret=-EINVAL;
+               }
+               break;
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = (struct v4l2_format *)arg;
+
+               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+
+               memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+               f->fmt.pix.width        = fh->width;
+               f->fmt.pix.height       = fh->height;
+               f->fmt.pix.field        = fh->vb_vidq.field;
+               f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+               f->fmt.pix.bytesperline =
+                       (f->fmt.pix.width * fh->fmt->depth) >> 3;
+               f->fmt.pix.sizeimage =
+                       f->fmt.pix.height * f->fmt.pix.bytesperline;
+               break;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+
+               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       dprintk(1,"Only capture supported.\n");
+                       ret=-EINVAL;
+                       break;
+               }
+
+               ret = vivi_try_fmt(dev,fh,f);
+               if (ret < 0)
+                       break;
+
+               fh->fmt           = &format;
+               fh->width         = f->fmt.pix.width;
+               fh->height        = f->fmt.pix.height;
+               fh->vb_vidq.field = f->fmt.pix.field;
+               fh->type          = f->type;
+
+               break;
+       }
+       case VIDIOC_TRY_FMT:
+       {
+               struct v4l2_format *f = arg;
+               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+
+               ret=vivi_try_fmt(dev,fh,f);
+               break;
+       }
+       case VIDIOC_REQBUFS:
+               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+               ret=videobuf_reqbufs(&fh->vb_vidq, arg);
+               break;
+       case VIDIOC_QUERYBUF:
+               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+               ret=videobuf_querybuf(&fh->vb_vidq, arg);
+               break;
+       case VIDIOC_QBUF:
+               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+               ret=videobuf_qbuf(&fh->vb_vidq, arg);
+               break;
+       case VIDIOC_DQBUF:
+               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+               ret=videobuf_dqbuf(&fh->vb_vidq, arg,
+                                       file->f_flags & O_NONBLOCK);
+               break;
+#ifdef HAVE_V4L1
+       /* --- streaming capture ------------------------------------- */
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *mbuf = arg;
+               struct videobuf_queue *q=&fh->vb_vidq;
+               struct v4l2_requestbuffers req;
+               unsigned int i;
+
+               memset(&req,0,sizeof(req));
+               req.type   = q->type;
+               req.count  = 8;
+               req.memory = V4L2_MEMORY_MMAP;
+               ret = videobuf_reqbufs(q,&req);
+               if (ret < 0)
+                       break;
+               memset(mbuf,0,sizeof(*mbuf));
+               mbuf->frames = req.count;
+               mbuf->size   = 0;
+               for (i = 0; i < mbuf->frames; i++) {
+                       mbuf->offsets[i]  = q->bufs[i]->boff;
+                       mbuf->size       += q->bufs[i]->bsize;
+               }
+               break;
+       }
+#endif
+       case VIDIOC_STREAMON:
+       {
+               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               if (!res_get(dev,fh))
+                       return -EBUSY;
+               ret=videobuf_streamon(&fh->vb_vidq);
+               break;
+       }
+       case VIDIOC_STREAMOFF:
+       {
+               if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       ret=-EINVAL;
+                       break;
+               }
+               ret = videobuf_streamoff(&fh->vb_vidq);
+               if (ret < 0)
+                       break;
+               res_free(dev,fh);
+               break;
+       }
+       /* ---------- tv norms ---------- */
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *e = arg;
+
+               if (e->index>0) {
+                       ret=-EINVAL;
+                       break;
+               }
+               ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M");
+
+               /* Allows vivi to use different fps from video std */
+               e->frameperiod.numerator = WAKE_NUMERATOR;
+               e->frameperiod.denominator = WAKE_DENOMINATOR;
+
+               break;
+       }
+       case VIDIOC_G_STD:
+       {
+               v4l2_std_id *id = arg;
+
+               *id = V4L2_STD_NTSC_M;
+               break;
+       }
+       case VIDIOC_S_STD:
+       {
+               break;
+       }
+       /* ------ input switching ---------- */
+       case VIDIOC_ENUMINPUT:
+       { /* only one input in this sample driver */
+               struct v4l2_input *inp = arg;
+
+               if (inp->index != 0) {
+                       ret=-EINVAL;
+                       break;
+               }
+               memset(inp, 0, sizeof(*inp));
+
+               inp->index = 0;
+               inp->type = V4L2_INPUT_TYPE_CAMERA;
+               inp->std = V4L2_STD_NTSC_M;
+               strcpy(inp->name,"Camera");
+               break;
+       }
+       case VIDIOC_G_INPUT:
+       {
+               unsigned int *i = arg;
+
+               *i = 0;
+               break;
+       }
+       case VIDIOC_S_INPUT:
+       {
+               unsigned int *i = arg;
+
+               if (*i > 0)
+                       ret=-EINVAL;
+               break;
+       }
+
+       /* --- controls ---------------------------------------------- */
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *qc = arg;
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+                       if (qc->id && qc->id == vivi_qctrl[i].id) {
+                               memcpy(qc, &(vivi_qctrl[i]),
+                                       sizeof(*qc));
+                               break;
+                       }
+
+               ret=-EINVAL;
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+                       if (ctrl->id == vivi_qctrl[i].id) {
+                               ctrl->value=qctl_regs[i];
+                               break;
+                       }
+
+               ret=-EINVAL;
+               break;
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               int i;
+               for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+                       if (ctrl->id == vivi_qctrl[i].id) {
+                               if (ctrl->value <
+                                       vivi_qctrl[i].minimum
+                                       || ctrl->value >
+                                       vivi_qctrl[i].maximum) {
+                                               ret=-ERANGE;
+                                               break;
+                                       }
+                               qctl_regs[i]=ctrl->value;
+                               break;
+                       }
+               ret=-EINVAL;
+               break;
+       }
+       default:
+               ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl);
+       }
+
+       if (debug) {
+               if (ret<0) {
+                       v4l_print_ioctl("vivi(err)", cmd);
+                       dprintk(1,"errcode=%d\n",ret);
+               } else if (_IOC_DIR(cmd) & _IOC_READ)
+                       v4l_printk_ioctl_arg("vivi(r)",cmd, arg);
+       }
+
+       return ret;
+}
+
+static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+}
+
+/* ------------------------------------------------------------------
+       File operations for the device
+   ------------------------------------------------------------------*/
+
+#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8)
+
+static int vivi_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct vivi_dev *h,*dev = NULL;
+       struct vivi_fh *fh;
+       struct list_head *list;
+       enum v4l2_buf_type type = 0;
+       int i;
+
+       printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
+
+       list_for_each(list,&vivi_devlist) {
+               h = list_entry(list, struct vivi_dev, vivi_devlist);
+               if (h->video_dev.minor == minor) {
+                       dev  = h;
+                       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               }
+       }
+       if (NULL == dev)
+               return -ENODEV;
+
+
+       /* If more than one user, mutex should be added */
+       dev->users++;
+
+       dprintk(1,"open minor=%d type=%s users=%d\n",
+                               minor,v4l2_type_names[type],dev->users);
+
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+       if (NULL == fh) {
+               dev->users--;
+               return -ENOMEM;
+       }
+
+       file->private_data = fh;
+       fh->dev      = dev;
+       fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fh->fmt      = &format;
+       fh->width    = 640;
+       fh->height   = 480;
+
+       /* Put all controls at a sane state */
+       for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+               qctl_regs[i] =vivi_qctrl[i].default_value;
+
+       dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+               (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
+       dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued));
+       dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active));
+
+       /* Resets frame counters */
+       dev->h=0;
+       dev->m=0;
+       dev->s=0;
+       dev->us=0;
+       dev->jiffies=jiffies;
+       sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
+                       dev->h,dev->m,dev->s,(dev->us+500)/1000);
+
+       videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
+                       NULL, NULL,
+                       fh->type,
+                       V4L2_FIELD_INTERLACED,
+                       sizeof(struct vivi_buffer),fh);
+
+       return 0;
+}
+
+static ssize_t
+vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+       struct vivi_fh *fh = file->private_data;
+
+       if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (res_locked(fh->dev))
+                       return -EBUSY;
+               return videobuf_read_one(&fh->vb_vidq, data, count, ppos,
+                                       file->f_flags & O_NONBLOCK);
+       }
+       return 0;
+}
+
+static unsigned int
+vivi_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct vivi_fh *fh = file->private_data;
+       struct vivi_buffer *buf;
+
+       dprintk(1,"%s\n",__FUNCTION__);
+
+       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+               return POLLERR;
+
+       if (res_get(fh->dev,fh)) {
+               dprintk(1,"poll: mmap interface\n");
+               /* streaming capture */
+               if (list_empty(&fh->vb_vidq.stream))
+                       return POLLERR;
+               buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream);
+       } else {
+               dprintk(1,"poll: read() interface\n");
+               /* read() capture */
+               buf = (struct vivi_buffer*)fh->vb_vidq.read_buf;
+               if (NULL == buf)
+                       return POLLERR;
+       }
+       poll_wait(file, &buf->vb.done, wait);
+       if (buf->vb.state == STATE_DONE ||
+           buf->vb.state == STATE_ERROR)
+               return POLLIN|POLLRDNORM;
+       return 0;
+}
+
+static int vivi_release(struct inode *inode, struct file *file)
+{
+       struct vivi_fh  *fh     = file->private_data;
+       struct vivi_dev *dev    = fh->dev;
+       struct vivi_dmaqueue *vidq = &dev->vidq;
+
+       int minor = iminor(inode);
+
+       vivi_stop_thread(vidq);
+       videobuf_mmap_free(&fh->vb_vidq);
+
+       kfree (fh);
+
+       dev->users--;
+
+       printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users);
+
+       return 0;
+}
+
+static int
+vivi_mmap(struct file *file, struct vm_area_struct * vma)
+{
+       struct vivi_fh *fh = file->private_data;
+       int ret;
+
+       dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
+
+       ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+       dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n",
+               (unsigned long)vma->vm_start,
+               (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+               ret);
+
+       return ret;
+}
+
+static struct file_operations vivi_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vivi_open,
+       .release        = vivi_release,
+       .read           = vivi_read,
+       .poll           = vivi_poll,
+       .ioctl          = vivi_ioctl,
+       .mmap           = vivi_mmap,
+       .llseek         = no_llseek,
+};
+
+static struct video_device vivi = {
+       .name           = "VTM Virtual Video Capture Board",
+       .type           = VID_TYPE_CAPTURE,
+       .hardware       = 0,
+       .fops           = &vivi_fops,
+       .minor          = -1,
+//     .release        = video_device_release,
+};
+/* ------------------------------------------------------------------
+       Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+static int __init vivi_init(void)
+{
+       int ret;
+       struct vivi_dev *dev;
+
+       dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+       if (NULL == dev)
+               return -ENOMEM;
+       list_add_tail(&dev->vivi_devlist,&vivi_devlist);
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       INIT_LIST_HEAD(&dev->vidq.queued);
+
+       /* initialize locks */
+       init_MUTEX(&dev->lock);
+
+       dev->vidq.timeout.function = vivi_vid_timeout;
+       dev->vidq.timeout.data     = (unsigned long)dev;
+       init_timer(&dev->vidq.timeout);
+
+       ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
+       printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
+       return ret;
+}
+
+static void __exit vivi_exit(void)
+{
+       struct vivi_dev *h;
+       struct list_head *list;
+
+       list_for_each(list,&vivi_devlist) {
+               h = list_entry(list, struct vivi_dev, vivi_devlist);
+               kfree (h);
+       }
+       video_unregister_device(&vivi);
+}
+
+module_init(vivi_init);
+module_exit(vivi_exit);
index 4cd579967487a155ed1de31335fd67993fd19efc..40b205b91481e495812c727da02baee30017834e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1
  *
  * Copyright (C) 2001 Laurent Pinchart <lpinchart@freegates.be>
@@ -176,8 +176,8 @@ vpx3220_write_block (struct i2c_client *client,
 
 static int
 vpx3220_write_fp_block (struct i2c_client *client,
-                       const u16         *data,
-                       unsigned int       len)
+                       const u16         *data,
+                       unsigned int       len)
 {
        u8 reg;
        int ret = 0;
@@ -316,7 +316,7 @@ vpx3220_command (struct i2c_client *client,
                vpx3220_write_fp_block(client, init_fp,
                                       sizeof(init_fp) >> 1);
                switch (decoder->norm) {
-                       
+
                case VIDEO_MODE_NTSC:
                        vpx3220_write_fp_block(client, init_ntsc,
                                               sizeof(init_ntsc) >> 1);
@@ -324,7 +324,7 @@ vpx3220_command (struct i2c_client *client,
 
                case VIDEO_MODE_PAL:
                        vpx3220_write_fp_block(client, init_pal,
-                                              sizeof(init_pal) >> 1);
+                                              sizeof(init_pal) >> 1);
                        break;
                case VIDEO_MODE_SECAM:
                        vpx3220_write_fp_block(client, init_secam,
@@ -332,10 +332,10 @@ vpx3220_command (struct i2c_client *client,
                        break;
                default:
                        vpx3220_write_fp_block(client, init_pal,
-                                              sizeof(init_pal) >> 1);
+                                              sizeof(init_pal) >> 1);
                        break;
                }
-       }               
+       }
                break;
 
        case DECODER_DUMP:
@@ -411,7 +411,7 @@ vpx3220_command (struct i2c_client *client,
 
                /* Here we back up the input selection because it gets
                   overwritten when we fill the registers with the
-                   choosen video norm */
+                  choosen video norm */
                temp_input = vpx3220_fp_read(client, 0xf2);
 
                dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n",
@@ -578,7 +578,7 @@ static unsigned short normal_i2c[] =
 };
 
 static unsigned short ignore = I2C_CLIENT_END;
-                                                                                
+
 static struct i2c_client_address_data addr_data = {
        .normal_i2c             = normal_i2c,
        .probe                  = &ignore,
@@ -661,7 +661,7 @@ vpx3220_detect_client (struct i2c_adapter *adapter,
                        break;
                default:
                        dprintk(1,
-                               KERN_INFO 
+                               KERN_INFO
                                "%s: Wrong part number (0x%04x)\n",
                                __func__, pn);
                        kfree(client);
index b7b0afffd21434b0fb7bc2c0e24c79175b063b42..80ef8a1b8f632ddb83656626dabdc26b5722d0a3 100644 (file)
@@ -26,7 +26,7 @@
        Does any other model using the w9966 interface chip exist ?
 
        Todo:
-       
+
        *Add a working EPP mode, since DMA ECP read isn't implemented
        in the parport drivers. (That's why it's so sloow)
 
@@ -47,9 +47,9 @@
        *Probably some bugs that I don't know of
 
        Please support me by sending feedback!
-       
+
        Changes:
-       
+
        Alan Cox:       Removed RGB mode for kernel merge, added THIS_MODULE
                        and owner support for newer module locks
 */
@@ -204,7 +204,7 @@ static struct video_device w9966_template = {
  */
 
 
-// Set camera phase flags, so we know what to uninit when terminating 
+// Set camera phase flags, so we know what to uninit when terminating
 static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
 {
        cam->dev_state = (cam->dev_state & ~mask) ^ val;
@@ -233,7 +233,7 @@ static inline void w9966_pdev_release(struct w9966_dev* cam)
        parport_release(cam->pdev);
        w9966_setState(cam, W9966_STATE_CLAIMED, 0);
 }
+
 // Read register from W9966 interface-chip
 // Expects a claimed pdev
 // -1 on error, else register data (byte)
@@ -242,7 +242,7 @@ static int w9966_rReg(struct w9966_dev* cam, int reg)
        // ECP, read, regtransfer, REG, REG, REG, REG, REG
        const unsigned char addr = 0x80 | (reg & 0x1f);
        unsigned char val;
-       
+
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
                return -1;
        if (parport_write(cam->pport, &addr, 1) != 1)
@@ -263,7 +263,7 @@ static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
        // ECP, write, regtransfer, REG, REG, REG, REG, REG
        const unsigned char addr = 0xc0 | (reg & 0x1f);
        const unsigned char val = data;
-       
+
        if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
                return -1;
        if (parport_write(cam->pport, &addr, 1) != 1)
@@ -284,7 +284,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
 {
        if (cam->dev_state != 0)
                return -1;
-       
+
        cam->pport = port;
        cam->brightness = 128;
        cam->contrast = 64;
@@ -302,7 +302,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
                        cam->ppmode = IEEE1284_MODE_EPP;
                else
                        cam->ppmode = IEEE1284_MODE_ECP;
-               break;  
+               break;
        case 1:         // hw- or sw-ecp
                cam->ppmode = IEEE1284_MODE_ECP;
                break;
@@ -310,7 +310,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
                cam->ppmode = IEEE1284_MODE_EPP;
        break;
        }
-       
+
 // Tell the parport driver that we exists
        cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
        if (cam->pdev == NULL) {
@@ -320,7 +320,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
        w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
 
        w9966_pdev_claim(cam);
-       
+
 // Setup a default capture mode
        if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
                DPRINTF("w9966_setup() failed.\n");
@@ -333,11 +333,11 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
        memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
        cam->vdev.priv = cam;
 
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)                 
+       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
                return -1;
-       
+
        w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
-       
+
        // All ok
        printk(
                "w9966cf: Found and initialized a webcam on %s.\n",
@@ -391,7 +391,7 @@ static int w9966_findlen(int near, int size, int maxlen)
                // Only continue as long as we keep getting better values
                if (err > besterr)
                        break;
-               
+
                besterr = err;
                bestlen = len;
        }
@@ -399,7 +399,7 @@ static int w9966_findlen(int near, int size, int maxlen)
        return bestlen;
 }
 
-// Modify capture window (if necessary) 
+// Modify capture window (if necessary)
 // and calculate downscaling
 // Return -1 on error
 static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
@@ -407,7 +407,7 @@ static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsig
        int maxlen = max - min;
        int len = *end - *beg + 1;
        int newlen = w9966_findlen(len, size, maxlen);
-       int err = newlen - len; 
+       int err = newlen - len;
 
        // Check for bad format
        if (newlen > maxlen || newlen < size)
@@ -452,8 +452,8 @@ static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, in
                0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
        };
-       
-       
+
+
        if (w*h*2 > W9966_SRAMSIZE)
        {
                DPRINTF("capture window exceeds SRAM size!.\n");
@@ -469,9 +469,9 @@ static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, in
        cam->width = w;
        cam->height = h;
 
-       enh_s = 0;      
+       enh_s = 0;
        enh_e = w*h*2;
-       
+
 // Modify capture window if necessary and calculate downscaling
        if (
                w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
@@ -482,14 +482,14 @@ static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, in
                "%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
                w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
        );
-       
+
 // Setup registers
        regs[0x00] = 0x00;                      // Set normal operation
        regs[0x01] = 0x18;                      // Capture mode
        regs[0x02] = scale_y;                   // V-scaling
        regs[0x03] = scale_x;                   // H-scaling
-       
-       // Capture window       
+
+       // Capture window
        regs[0x04] = (x1 & 0x0ff);              // X-start (8 low bits)
        regs[0x05] = (x1 & 0x300)>>8;           // X-start (2 high bits)
        regs[0x06] = (y1 & 0x0ff);              // Y-start (8 low bits)
@@ -499,7 +499,7 @@ static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, in
        regs[0x0a] = (y2 & 0x0ff);              // Y-end (8 low bits)
 
        regs[0x0c] = W9966_SRAMID;              // SRAM-banks (1x 128kb)
-       
+
        // Enhancement layer
        regs[0x0d] = (enh_s& 0x000ff);          // Enh. start (0-7)
        regs[0x0e] = (enh_s& 0x0ff00)>>8;       // Enh. start (8-15)
@@ -515,7 +515,7 @@ static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, in
        regs[0x19] = 0xff;                      // I/O port direction control
        regs[0x1a] = 0xff;                      // I/O port data register
        regs[0x1b] = 0x10;                      // ???
-       
+
        // SAA7111 chip settings
        saa7111_regs[0x0a] = cam->brightness;
        saa7111_regs[0x0b] = cam->contrast;
@@ -551,7 +551,7 @@ static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
                cam->i2c_state |= W9966_I2C_W_DATA;
        else
                cam->i2c_state &= ~W9966_I2C_W_DATA;
-       
+
        w9966_wReg(cam, 0x18, cam->i2c_state);
        udelay(5);
 }
@@ -577,7 +577,7 @@ static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
 
        w9966_wReg(cam, 0x18, cam->i2c_state);
        udelay(5);
-       
+
        // we go to high, we also expect the peripheral to ack.
        if (state) {
                timeout = jiffies + 100;
@@ -607,16 +607,16 @@ static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
                w9966_i2c_setsda(cam, (data >> i) & 0x01);
 
                if (w9966_i2c_setscl(cam, 1) == -1)
-                       return -1;                      
+                       return -1;
                w9966_i2c_setscl(cam, 0);
        }
 
        w9966_i2c_setsda(cam, 1);
-       
+
        if (w9966_i2c_setscl(cam, 1) == -1)
                return -1;
        w9966_i2c_setscl(cam, 0);
-       
+
        return 0;
 }
 
@@ -626,8 +626,8 @@ static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
 static int w9966_i2c_rbyte(struct w9966_dev* cam)
 {
        unsigned char data = 0x00;
-       int i;  
-       
+       int i;
+
        w9966_i2c_setsda(cam, 1);
 
        for (i = 0; i < 8; i++)
@@ -637,7 +637,7 @@ static int w9966_i2c_rbyte(struct w9966_dev* cam)
                data = data << 1;
                if (w9966_i2c_getsda(cam))
                        data |= 0x01;
-               
+
                w9966_i2c_setscl(cam, 0);
        }
        return data;
@@ -673,11 +673,11 @@ static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
                return -1;
 
        w9966_i2c_setsda(cam, 0);
-       
+
        if (w9966_i2c_setscl(cam, 1) == -1)
                return -1;
        w9966_i2c_setsda(cam, 1);
-       
+
        return data;
 }
 #endif
@@ -699,7 +699,7 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
        w9966_i2c_setsda(cam, 0);
        if (w9966_i2c_setscl(cam, 1) == -1)
                return -1;
-               
+
        w9966_i2c_setsda(cam, 1);
 
        return 0;
@@ -714,7 +714,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
 {
        struct video_device *vdev = video_devdata(file);
        struct w9966_dev *cam = vdev->priv;
-       
+
        switch(cmd)
        {
        case VIDIOCGCAP:
@@ -790,14 +790,14 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
                struct video_picture *vpic = arg;
                if (vpic->depth != 16 || vpic->palette != VIDEO_PALETTE_YUV422)
                        return -EINVAL;
-                       
+
                cam->brightness = vpic->brightness >> 8;
                cam->hue = (vpic->hue >> 8) - 128;
                cam->color = vpic->colour >> 9;
                cam->contrast = vpic->contrast >> 9;
 
                w9966_pdev_claim(cam);
-               
+
                if (
                        w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
                        w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
@@ -807,7 +807,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
                        w9966_pdev_release(cam);
                        return -EIO;
                }
-               
+
                w9966_pdev_release(cam);
                return 0;
        }
@@ -815,13 +815,13 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
        {
                int ret;
                struct video_window *vwin = arg;
-               
+
                if (vwin->flags != 0)
                        return -EINVAL;
                if (vwin->clipcount != 0)
                        return -EINVAL;
                if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
-                       return -EINVAL;         
+                       return -EINVAL;
                if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
                        return -EINVAL;
 
@@ -829,12 +829,12 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
                w9966_pdev_claim(cam);
                ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
                w9966_pdev_release(cam);
-               
+
                if (ret != 0) {
                        DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
                        return -EIO;
                }
-               
+
                return 0;
        }
        case VIDIOCGWIN:
@@ -846,7 +846,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
                return 0;
        }
        // Unimplemented
-       case VIDIOCCAPTURE:     
+       case VIDIOCCAPTURE:
        case VIDIOCGFBUF:
        case VIDIOCSFBUF:
        case VIDIOCKEY:
@@ -877,17 +877,17 @@ static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
        unsigned char __user *dest = (unsigned char __user *)buf;
        unsigned long dleft = count;
        unsigned char *tbuf;
-       
+
        // Why would anyone want more than this??
        if (count > cam->width * cam->height * 2)
                return -EINVAL;
-       
+
        w9966_pdev_claim(cam);
        w9966_wReg(cam, 0x00, 0x02);    // Reset ECP-FIFO buffer
        w9966_wReg(cam, 0x00, 0x00);    // Return to normal operation
        w9966_wReg(cam, 0x01, 0x98);    // Enable capture
 
-       // write special capture-addr and negotiate into data transfer  
+       // write special capture-addr and negotiate into data transfer
        if (
                (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0  )||
                (parport_write(cam->pport, &addr, 1) != 1                                               )||
@@ -906,7 +906,7 @@ static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
        while(dleft > 0)
        {
                unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
-       
+
                if (parport_read(cam->pport, tbuf, tsize) < tsize) {
                        count = -EFAULT;
                        goto out;
@@ -933,7 +933,7 @@ out:
 static void w9966_attach(struct parport *port)
 {
        int i;
-       
+
        for (i = 0; i < W9966_MAXCAMS; i++)
        {
                if (w9966_cams[i].dev_state != 0)       // Cam is already assigned
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
new file mode 100644 (file)
index 0000000..20f211b
--- /dev/null
@@ -0,0 +1,3691 @@
+/***************************************************************************
+ * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
+ *                                                                         *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * - Memory management code from bttv driver by Ralph Metzler,             *
+ *   Marcus Metzler and Gerd Knorr.                                        *
+ * - I2C interface to kernel, high-level image sensor control routines and *
+ *   some symbolic names from OV511 driver by Mark W. McClelland.          *
+ * - Low-level I2C fast write function by Piotr Czerczak.                  *
+ * - Low-level I2C read function by Frederic Jouault.                      *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <linux/page-flags.h>
+#include <linux/moduleparam.h>
+
+#include "w9968cf.h"
+#include "w9968cf_decoder.h"
+
+static struct w9968cf_vpp_t* w9968cf_vpp;
+static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
+
+static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
+static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
+
+static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
+
+
+/****************************************************************************
+ * Module macros and parameters                                             *
+ ****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, winbond_id_table);
+
+MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
+MODULE_VERSION(W9968CF_MODULE_VERSION);
+MODULE_LICENSE(W9968CF_MODULE_LICENSE);
+MODULE_SUPPORTED_DEVICE("Video");
+
+static int ovmod_load = W9968CF_OVMOD_LOAD;
+static unsigned short simcams = W9968CF_SIMCAMS;
+static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
+static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                    W9968CF_PACKET_SIZE};
+static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                      W9968CF_BUFFERS};
+static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                             W9968CF_DOUBLE_BUFFER};
+static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
+static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] =
+                                     W9968CF_FILTER_TYPE};
+static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
+static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                        W9968CF_DECOMPRESSION};
+static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
+static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
+static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
+static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
+static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
+static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                    W9968CF_LIGHTFREQ};
+static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
+                             W9968CF_BANDINGFILTER};
+static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
+static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
+static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
+static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
+static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                   W9968CF_BRIGHTNESS};
+static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
+static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
+static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                 W9968CF_CONTRAST};
+static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+                                  W9968CF_WHITENESS};
+#ifdef W9968CF_DEBUG
+static unsigned short debug = W9968CF_DEBUG_LEVEL;
+static int specific_debug = W9968CF_SPECIFIC_DEBUG;
+#endif
+
+static unsigned int param_nv[24]; /* number of values per parameter */
+
+#ifdef CONFIG_KMOD
+module_param(ovmod_load, bool, 0644);
+#endif
+module_param(simcams, ushort, 0644);
+module_param_array(video_nr, short, &param_nv[0], 0444);
+module_param_array(packet_size, uint, &param_nv[1], 0444);
+module_param_array(max_buffers, ushort, &param_nv[2], 0444);
+module_param_array(double_buffer, bool, &param_nv[3], 0444);
+module_param_array(clamping, bool, &param_nv[4], 0444);
+module_param_array(filter_type, ushort, &param_nv[5], 0444);
+module_param_array(largeview, bool, &param_nv[6], 0444);
+module_param_array(decompression, ushort, &param_nv[7], 0444);
+module_param_array(upscaling, bool, &param_nv[8], 0444);
+module_param_array(force_palette, ushort, &param_nv[9], 0444);
+module_param_array(force_rgb, ushort, &param_nv[10], 0444);
+module_param_array(autobright, bool, &param_nv[11], 0444);
+module_param_array(autoexp, bool, &param_nv[12], 0444);
+module_param_array(lightfreq, ushort, &param_nv[13], 0444);
+module_param_array(bandingfilter, bool, &param_nv[14], 0444);
+module_param_array(clockdiv, short, &param_nv[15], 0444);
+module_param_array(backlight, bool, &param_nv[16], 0444);
+module_param_array(mirror, bool, &param_nv[17], 0444);
+module_param_array(monochrome, bool, &param_nv[18], 0444);
+module_param_array(brightness, uint, &param_nv[19], 0444);
+module_param_array(hue, uint, &param_nv[20], 0444);
+module_param_array(colour, uint, &param_nv[21], 0444);
+module_param_array(contrast, uint, &param_nv[22], 0444);
+module_param_array(whiteness, uint, &param_nv[23], 0444);
+#ifdef W9968CF_DEBUG
+module_param(debug, ushort, 0644);
+module_param(specific_debug, bool, 0644);
+#endif
+
+#ifdef CONFIG_KMOD
+MODULE_PARM_DESC(ovmod_load,
+                "\n<0|1> Automatic 'ovcamchip' module loading."
+                "\n0 disabled, 1 enabled."
+                "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
+                "\nmodule in the system, according to its configuration, and"
+                "\nattempts to load that module automatically. This action is"
+                "\nperformed once as soon as the 'w9968cf' module is loaded"
+                "\ninto memory."
+                "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
+                "\n");
+#endif
+MODULE_PARM_DESC(simcams,
+                "\n<n> Number of cameras allowed to stream simultaneously."
+                "\nn may vary from 0 to "
+                __MODULE_STRING(W9968CF_MAX_DEVICES)"."
+                "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
+                "\n");
+MODULE_PARM_DESC(video_nr,
+                "\n<-1|n[,...]> Specify V4L minor mode number."
+                "\n -1 = use next available (default)"
+                "\n  n = use minor number n (integer >= 0)"
+                "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
+                " cameras this way."
+                "\nFor example:"
+                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                "\nthe second camera and use auto for the first"
+                "\none and for every other camera."
+                "\n");
+MODULE_PARM_DESC(packet_size,
+                "\n<n[,...]> Specify the maximum data payload"
+                "\nsize in bytes for alternate settings, for each device."
+                "\nn is scaled between 63 and 1023 "
+                "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
+                "\n");
+MODULE_PARM_DESC(max_buffers,
+                "\n<n[,...]> For advanced users."
+                "\nSpecify the maximum number of video frame buffers"
+                "\nto allocate for each device, from 2 to "
+                __MODULE_STRING(W9968CF_MAX_BUFFERS)
+                ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
+                "\n");
+MODULE_PARM_DESC(double_buffer,
+                "\n<0|1[,...]> "
+                "Hardware double buffering: 0 disabled, 1 enabled."
+                "\nIt should be enabled if you want smooth video output: if"
+                "\nyou obtain out of sync. video, disable it, or try to"
+                "\ndecrease the 'clockdiv' module parameter value."
+                "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(clamping,
+                "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
+                "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(filter_type,
+                "\n<0|1|2[,...]> Video filter type."
+                "\n0 none, 1 (1-2-1) 3-tap filter, "
+                "2 (2-3-6-3-2) 5-tap filter."
+                "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
+                " for every device."
+                "\nThe filter is used to reduce noise and aliasing artifacts"
+                "\nproduced by the CCD or CMOS image sensor, and the scaling"
+                " process."
+                "\n");
+MODULE_PARM_DESC(largeview,
+                "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
+                "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(upscaling,
+                "\n<0|1[,...]> Software scaling (for non-compressed video):"
+                "\n0 disabled, 1 enabled."
+                "\nDisable it if you have a slow CPU or you don't have"
+                " enough memory."
+                "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
+                " for every device."
+                "\nIf 'w9968cf-vpp' is not present, this parameter is"
+                " set to 0."
+                "\n");
+MODULE_PARM_DESC(decompression,
+                "\n<0|1|2[,...]> Software video decompression:"
+                "\n- 0 disables decompression (doesn't allow formats needing"
+                " decompression)"
+                "\n- 1 forces decompression (allows formats needing"
+                " decompression only);"
+                "\n- 2 allows any permitted formats."
+                "\nFormats supporting compressed video are YUV422P and"
+                " YUV420P/YUV420 "
+                "\nin any resolutions where both width and height are "
+                "a multiple of 16."
+                "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
+                " for every device."
+                "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
+                "\nnot allowed; in this case this parameter is set to 2."
+                "\n");
+MODULE_PARM_DESC(force_palette,
+                "\n<0"
+                "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
+                "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
+                "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
+                "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
+                "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
+                "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
+                "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
+                "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
+                "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
+                "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
+                "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
+                "[,...]>"
+                " Force picture palette."
+                "\nIn order:"
+                "\n- 0 allows any of the following formats:"
+                "\n- UYVY    16 bpp - Original video, compression disabled"
+                "\n- YUV420  12 bpp - Original video, compression enabled"
+                "\n- YUV422P 16 bpp - Original video, compression enabled"
+                "\n- YUV420P 12 bpp - Original video, compression enabled"
+                "\n- YUVY    16 bpp - Software conversion from UYVY"
+                "\n- YUV422  16 bpp - Software conversion from UYVY"
+                "\n- GREY     8 bpp - Software conversion from UYVY"
+                "\n- RGB555  16 bpp - Software conversion from UYVY"
+                "\n- RGB565  16 bpp - Software conversion from UYVY"
+                "\n- RGB24   24 bpp - Software conversion from UYVY"
+                "\n- RGB32   32 bpp - Software conversion from UYVY"
+                "\nWhen not 0, this parameter will override 'decompression'."
+                "\nDefault value is 0 for every device."
+                "\nInitial palette is "
+                __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
+                "\nIf 'w9968cf-vpp' is not present, this parameter is"
+                " set to 9 (UYVY)."
+                "\n");
+MODULE_PARM_DESC(force_rgb,
+                "\n<0|1[,...]> Read RGB video data instead of BGR:"
+                "\n 1 = use RGB component ordering."
+                "\n 0 = use BGR component ordering."
+                "\nThis parameter has effect when using RGBX palettes only."
+                "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(autobright,
+                "\n<0|1[,...]> Image sensor automatically changes brightness:"
+                "\n 0 = no, 1 = yes"
+                "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(autoexp,
+                "\n<0|1[,...]> Image sensor automatically changes exposure:"
+                "\n 0 = no, 1 = yes"
+                "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(lightfreq,
+                "\n<50|60[,...]> Light frequency in Hz:"
+                "\n 50 for European and Asian lighting,"
+                " 60 for American lighting."
+                "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(bandingfilter,
+                "\n<0|1[,...]> Banding filter to reduce effects of"
+                " fluorescent lighting:"
+                "\n 0 disabled, 1 enabled."
+                "\nThis filter tries to reduce the pattern of horizontal"
+                "\nlight/dark bands caused by some (usually fluorescent)"
+                " lighting."
+                "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(clockdiv,
+                "\n<-1|n[,...]> "
+                "Force pixel clock divisor to a specific value (for experts):"
+                "\n  n may vary from 0 to 127."
+                "\n -1 for automatic value."
+                "\nSee also the 'double_buffer' module parameter."
+                "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(backlight,
+                "\n<0|1[,...]> Objects are lit from behind:"
+                "\n 0 = no, 1 = yes"
+                "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(mirror,
+                "\n<0|1[,...]> Reverse image horizontally:"
+                "\n 0 = no, 1 = yes"
+                "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(monochrome,
+                "\n<0|1[,...]> Use image sensor as monochrome sensor:"
+                "\n 0 = no, 1 = yes"
+                "\nNot all the sensors support monochrome color."
+                "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(brightness,
+                "\n<n[,...]> Set picture brightness (0-65535)."
+                "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
+                " for every device."
+                "\nThis parameter has no effect if 'autobright' is enabled."
+                "\n");
+MODULE_PARM_DESC(hue,
+                "\n<n[,...]> Set picture hue (0-65535)."
+                "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(colour,
+                "\n<n[,...]> Set picture saturation (0-65535)."
+                "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(contrast,
+                "\n<n[,...]> Set picture contrast (0-65535)."
+                "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
+                " for every device."
+                "\n");
+MODULE_PARM_DESC(whiteness,
+                "\n<n[,...]> Set picture whiteness (0-65535)."
+                "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
+                " for every device."
+                "\n");
+#ifdef W9968CF_DEBUG
+MODULE_PARM_DESC(debug,
+                "\n<n> Debugging information level, from 0 to 6:"
+                "\n0 = none (use carefully)"
+                "\n1 = critical errors"
+                "\n2 = significant informations"
+                "\n3 = configuration or general messages"
+                "\n4 = warnings"
+                "\n5 = called functions"
+                "\n6 = function internals"
+                "\nLevel 5 and 6 are useful for testing only, when only "
+                "one device is used."
+                "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
+                "\n");
+MODULE_PARM_DESC(specific_debug,
+                "\n<0|1> Enable or disable specific debugging messages:"
+                "\n0 = print messages concerning every level"
+                " <= 'debug' level."
+                "\n1 = print messages concerning the level"
+                " indicated by 'debug'."
+                "\nDefault value is "
+                __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
+                "\n");
+#endif /* W9968CF_DEBUG */
+
+
+
+/****************************************************************************
+ * Some prototypes                                                          *
+ ****************************************************************************/
+
+/* Video4linux interface */
+static struct file_operations w9968cf_fops;
+static int w9968cf_open(struct inode*, struct file*);
+static int w9968cf_release(struct inode*, struct file*);
+static int w9968cf_mmap(struct file*, struct vm_area_struct*);
+static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
+static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);
+static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int,
+                            void __user *);
+
+/* USB-specific */
+static int w9968cf_start_transfer(struct w9968cf_device*);
+static int w9968cf_stop_transfer(struct w9968cf_device*);
+static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
+static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
+static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
+static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
+static int w9968cf_read_sb(struct w9968cf_device*);
+static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
+static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
+
+/* Low-level I2C (SMBus) I/O */
+static int w9968cf_smbus_start(struct w9968cf_device*);
+static int w9968cf_smbus_stop(struct w9968cf_device*);
+static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
+static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
+static int w9968cf_smbus_write_ack(struct w9968cf_device*);
+static int w9968cf_smbus_read_ack(struct w9968cf_device*);
+static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
+static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
+                                     u16 address, u8* value);
+static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address,
+                                          u8 subaddress, u8* value);
+static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
+                                      u16 address, u8 subaddress);
+static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
+                                               u16 address, u8 subaddress,
+                                               u8 value);
+
+/* I2C interface to kernel */
+static int w9968cf_i2c_init(struct w9968cf_device*);
+static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
+                                 unsigned short flags, char read_write,
+                                 u8 command, int size, union i2c_smbus_data*);
+static u32 w9968cf_i2c_func(struct i2c_adapter*);
+static int w9968cf_i2c_attach_inform(struct i2c_client*);
+static int w9968cf_i2c_detach_inform(struct i2c_client*);
+static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
+                              unsigned long arg);
+
+/* Memory management */
+static void* rvmalloc(unsigned long size);
+static void rvfree(void *mem, unsigned long size);
+static void w9968cf_deallocate_memory(struct w9968cf_device*);
+static int  w9968cf_allocate_memory(struct w9968cf_device*);
+
+/* High-level image sensor control functions */
+static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
+static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
+static int w9968cf_sensor_cmd(struct w9968cf_device*,
+                             unsigned int cmd, void *arg);
+static int w9968cf_sensor_init(struct w9968cf_device*);
+static int w9968cf_sensor_update_settings(struct w9968cf_device*);
+static int w9968cf_sensor_get_picture(struct w9968cf_device*);
+static int w9968cf_sensor_update_picture(struct w9968cf_device*,
+                                        struct video_picture pict);
+
+/* Other helper functions */
+static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
+                                    enum w9968cf_model_id,
+                                    const unsigned short dev_nr);
+static void w9968cf_adjust_configuration(struct w9968cf_device*);
+static int w9968cf_turn_on_led(struct w9968cf_device*);
+static int w9968cf_init_chip(struct w9968cf_device*);
+static inline u16 w9968cf_valid_palette(u16 palette);
+static inline u16 w9968cf_valid_depth(u16 palette);
+static inline u8 w9968cf_need_decompression(u16 palette);
+static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
+static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
+static int w9968cf_postprocess_frame(struct w9968cf_device*,
+                                    struct w9968cf_frame_t*);
+static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
+static void w9968cf_init_framelist(struct w9968cf_device*);
+static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
+static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
+static void w9968cf_release_resources(struct w9968cf_device*);
+
+
+
+/****************************************************************************
+ * Symbolic names                                                           *
+ ****************************************************************************/
+
+/* Used to represent a list of values and their respective symbolic names */
+struct w9968cf_symbolic_list {
+       const int num;
+       const char *name;
+};
+
+/*--------------------------------------------------------------------------
+  Returns the name of the matching element in the symbolic_list array. The
+  end of the list must be marked with an element that has a NULL name.
+  --------------------------------------------------------------------------*/
+static inline const char *
+symbolic(struct w9968cf_symbolic_list list[], const int num)
+{
+       int i;
+
+       for (i = 0; list[i].name != NULL; i++)
+               if (list[i].num == num)
+                       return (list[i].name);
+
+       return "Unknown";
+}
+
+static struct w9968cf_symbolic_list camlist[] = {
+       { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
+       { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
+
+       /* Other cameras (having the same descriptors as Generic W996[87]CF) */
+       { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
+       { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
+       { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
+       { W9968CF_MOD_LL, "Lebon LDC-035A" },
+       { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
+       { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
+       { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
+       { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
+       { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
+
+       {  -1, NULL }
+};
+
+static struct w9968cf_symbolic_list senlist[] = {
+       { CC_OV76BE,   "OV76BE" },
+       { CC_OV7610,   "OV7610" },
+       { CC_OV7620,   "OV7620" },
+       { CC_OV7620AE, "OV7620AE" },
+       { CC_OV6620,   "OV6620" },
+       { CC_OV6630,   "OV6630" },
+       { CC_OV6630AE, "OV6630AE" },
+       { CC_OV6630AF, "OV6630AF" },
+       { -1, NULL }
+};
+
+/* Video4Linux1 palettes */
+static struct w9968cf_symbolic_list v4l1_plist[] = {
+       { VIDEO_PALETTE_GREY,    "GREY" },
+       { VIDEO_PALETTE_HI240,   "HI240" },
+       { VIDEO_PALETTE_RGB565,  "RGB565" },
+       { VIDEO_PALETTE_RGB24,   "RGB24" },
+       { VIDEO_PALETTE_RGB32,   "RGB32" },
+       { VIDEO_PALETTE_RGB555,  "RGB555" },
+       { VIDEO_PALETTE_YUV422,  "YUV422" },
+       { VIDEO_PALETTE_YUYV,    "YUYV" },
+       { VIDEO_PALETTE_UYVY,    "UYVY" },
+       { VIDEO_PALETTE_YUV420,  "YUV420" },
+       { VIDEO_PALETTE_YUV411,  "YUV411" },
+       { VIDEO_PALETTE_RAW,     "RAW" },
+       { VIDEO_PALETTE_YUV422P, "YUV422P" },
+       { VIDEO_PALETTE_YUV411P, "YUV411P" },
+       { VIDEO_PALETTE_YUV420P, "YUV420P" },
+       { VIDEO_PALETTE_YUV410P, "YUV410P" },
+       { -1, NULL }
+};
+
+/* Decoder error codes: */
+static struct w9968cf_symbolic_list decoder_errlist[] = {
+       { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
+       { W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
+       { W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },
+       { W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
+       { W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
+       { W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
+       { -1, NULL }
+};
+
+/* URB error codes: */
+static struct w9968cf_symbolic_list urb_errlist[] = {
+       { -ENOMEM,    "No memory for allocation of internal structures" },
+       { -ENOSPC,    "The host controller's bandwidth is already consumed" },
+       { -ENOENT,    "URB was canceled by unlink_urb" },
+       { -EXDEV,     "ISO transfer only partially completed" },
+       { -EAGAIN,    "Too match scheduled for the future" },
+       { -ENXIO,     "URB already queued" },
+       { -EFBIG,     "Too much ISO frames requested" },
+       { -ENOSR,     "Buffer error (overrun)" },
+       { -EPIPE,     "Specified endpoint is stalled (device not responding)"},
+       { -EOVERFLOW, "Babble (bad cable?)" },
+       { -EPROTO,    "Bit-stuff error (bad cable?)" },
+       { -EILSEQ,    "CRC/Timeout" },
+       { -ETIMEDOUT, "NAK (device does not respond)" },
+       { -1, NULL }
+};
+
+
+
+/****************************************************************************
+ * Memory management functions                                              *
+ ****************************************************************************/
+static void* rvmalloc(unsigned long size)
+{
+       void* mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+
+static void rvfree(void* mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+
+/*--------------------------------------------------------------------------
+  Deallocate previously allocated memory.
+  --------------------------------------------------------------------------*/
+static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
+{
+       u8 i;
+
+       /* Free the isochronous transfer buffers */
+       for (i = 0; i < W9968CF_URBS; i++) {
+               kfree(cam->transfer_buffer[i]);
+               cam->transfer_buffer[i] = NULL;
+       }
+
+       /* Free temporary frame buffer */
+       if (cam->frame_tmp.buffer) {
+               rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
+               cam->frame_tmp.buffer = NULL;
+       }
+
+       /* Free helper buffer */
+       if (cam->frame_vpp.buffer) {
+               rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
+               cam->frame_vpp.buffer = NULL;
+       }
+
+       /* Free video frame buffers */
+       if (cam->frame[0].buffer) {
+               rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
+               cam->frame[0].buffer = NULL;
+       }
+
+       cam->nbuffers = 0;
+
+       DBG(5, "Memory successfully deallocated")
+}
+
+
+/*--------------------------------------------------------------------------
+  Allocate memory buffers for USB transfers and video frames.
+  This function is called by open() only.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_allocate_memory(struct w9968cf_device* cam)
+{
+       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
+       void* buff = NULL;
+       unsigned long hw_bufsize, vpp_bufsize;
+       u8 i, bpp;
+
+       /* NOTE: Deallocation is done elsewhere in case of error */
+
+       /* Calculate the max amount of raw data per frame from the device */
+       hw_bufsize = cam->maxwidth*cam->maxheight*2;
+
+       /* Calculate the max buf. size needed for post-processing routines */
+       bpp = (w9968cf_vpp) ? 4 : 2;
+       if (cam->upscaling)
+               vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
+                                 cam->maxwidth*cam->maxheight*bpp);
+       else
+               vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
+
+       /* Allocate memory for the isochronous transfer buffers */
+       for (i = 0; i < W9968CF_URBS; i++) {
+               if (!(cam->transfer_buffer[i] =
+                     kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
+                       DBG(1, "Couldn't allocate memory for the isochronous "
+                              "transfer buffers (%u bytes)",
+                           p_size * W9968CF_ISO_PACKETS)
+                       return -ENOMEM;
+               }
+       }
+
+       /* Allocate memory for the temporary frame buffer */
+       if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
+               DBG(1, "Couldn't allocate memory for the temporary "
+                      "video frame buffer (%lu bytes)", hw_bufsize)
+               return -ENOMEM;
+       }
+       cam->frame_tmp.size = hw_bufsize;
+       cam->frame_tmp.number = -1;
+
+       /* Allocate memory for the helper buffer */
+       if (w9968cf_vpp) {
+               if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
+                       DBG(1, "Couldn't allocate memory for the helper buffer"
+                              " (%lu bytes)", vpp_bufsize)
+                       return -ENOMEM;
+               }
+               cam->frame_vpp.size = vpp_bufsize;
+       } else
+               cam->frame_vpp.buffer = NULL;
+
+       /* Allocate memory for video frame buffers */
+       cam->nbuffers = cam->max_buffers;
+       while (cam->nbuffers >= 2) {
+               if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
+                       break;
+               else
+                       cam->nbuffers--;
+       }
+
+       if (!buff) {
+               DBG(1, "Couldn't allocate memory for the video frame buffers")
+               cam->nbuffers = 0;
+               return -ENOMEM;
+       }
+
+       if (cam->nbuffers != cam->max_buffers)
+               DBG(2, "Couldn't allocate memory for %u video frame buffers. "
+                      "Only memory for %u buffers has been allocated",
+                   cam->max_buffers, cam->nbuffers)
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].buffer = buff + i*vpp_bufsize;
+               cam->frame[i].size = vpp_bufsize;
+               cam->frame[i].number = i;
+               /* Circular list */
+               if (i != cam->nbuffers-1)
+                       cam->frame[i].next = &cam->frame[i+1];
+               else
+                       cam->frame[i].next = &cam->frame[0];
+               cam->frame[i].status = F_UNUSED;
+       }
+
+       DBG(5, "Memory successfully allocated")
+       return 0;
+}
+
+
+
+/****************************************************************************
+ * USB-specific functions                                                   *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  This is an handler function which is called after the URBs are completed.
+  It collects multiple data packets coming from the camera by putting them
+  into frame buffers: one or more zero data length data packets are used to
+  mark the end of a video frame; the first non-zero data packet is the start
+  of the next video frame; if an error is encountered in a packet, the entire
+  video frame is discarded and grabbed again.
+  If there are no requested frames in the FIFO list, packets are collected into
+  a temporary buffer.
+  --------------------------------------------------------------------------*/
+static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
+       struct w9968cf_frame_t** f;
+       unsigned int len, status;
+       void* pos;
+       u8 i;
+       int err = 0;
+
+       if ((!cam->streaming) || cam->disconnected) {
+               DBG(4, "Got interrupt, but not streaming")
+               return;
+       }
+
+       /* "(*f)" will be used instead of "cam->frame_current" */
+       f = &cam->frame_current;
+
+       /* If a frame has been requested and we are grabbing into
+          the temporary frame, we'll switch to that requested frame */
+       if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
+               if (cam->frame_tmp.status == F_GRABBING) {
+                       w9968cf_pop_frame(cam, &cam->frame_current);
+                       (*f)->status = F_GRABBING;
+                       (*f)->length = cam->frame_tmp.length;
+                       memcpy((*f)->buffer, cam->frame_tmp.buffer,
+                              (*f)->length);
+                       DBG(6, "Switched from temp. frame to frame #%d",
+                           (*f)->number)
+               }
+       }
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status && len != 0) {
+                       DBG(4, "URB failed, error in data packet "
+                              "(error #%u, %s)",
+                           status, symbolic(urb_errlist, status))
+                       (*f)->status = F_ERROR;
+                       continue;
+               }
+
+               if (len) { /* start of frame */
+
+                       if ((*f)->status == F_UNUSED) {
+                               (*f)->status = F_GRABBING;
+                               (*f)->length = 0;
+                       }
+
+                       /* Buffer overflows shouldn't happen, however...*/
+                       if ((*f)->length + len > (*f)->size) {
+                               DBG(4, "Buffer overflow: bad data packets")
+                               (*f)->status = F_ERROR;
+                       }
+
+                       if ((*f)->status == F_GRABBING) {
+                               memcpy((*f)->buffer + (*f)->length, pos, len);
+                               (*f)->length += len;
+                       }
+
+               } else if ((*f)->status == F_GRABBING) { /* end of frame */
+
+                       DBG(6, "Frame #%d successfully grabbed", (*f)->number)
+
+                       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+                               err = w9968cf_vpp->check_headers((*f)->buffer,
+                                                                (*f)->length);
+                               if (err) {
+                                       DBG(4, "Skip corrupted frame: %s",
+                                           symbolic(decoder_errlist, err))
+                                       (*f)->status = F_UNUSED;
+                                       continue; /* grab this frame again */
+                               }
+                       }
+
+                       (*f)->status = F_READY;
+                       (*f)->queued = 0;
+
+                       /* Take a pointer to the new frame from the FIFO list.
+                          If the list is empty,we'll use the temporary frame*/
+                       if (*cam->requested_frame)
+                               w9968cf_pop_frame(cam, &cam->frame_current);
+                       else {
+                               cam->frame_current = &cam->frame_tmp;
+                               (*f)->status = F_UNUSED;
+                       }
+
+               } else if ((*f)->status == F_ERROR)
+                       (*f)->status = F_UNUSED; /* grab it again */
+
+               PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
+                     (unsigned long)(*f)->length, i, len, (*f)->status)
+
+       } /* end for */
+
+       /* Resubmit this URB */
+       urb->dev = cam->usbdev;
+       urb->status = 0;
+       spin_lock(&cam->urb_lock);
+       if (cam->streaming)
+               if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
+                       cam->misconfigured = 1;
+                       DBG(1, "Couldn't resubmit the URB: error %d, %s",
+                           err, symbolic(urb_errlist, err))
+               }
+       spin_unlock(&cam->urb_lock);
+
+       /* Wake up the user process */
+       wake_up_interruptible(&cam->wait_queue);
+}
+
+
+/*---------------------------------------------------------------------------
+  Setup the URB structures for the isochronous transfer.
+  Submit the URBs so that the data transfer begins.
+  Return 0 on success, a negative number otherwise.
+  ---------------------------------------------------------------------------*/
+static int w9968cf_start_transfer(struct w9968cf_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
+       u16 w, h, d;
+       int vidcapt;
+       u32 t_size;
+       int err = 0;
+       s8 i, j;
+
+       for (i = 0; i < W9968CF_URBS; i++) {
+               urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       for (j = 0; j < i; j++)
+                               usb_free_urb(cam->urb[j]);
+                       DBG(1, "Couldn't allocate the URB structures")
+                       return -ENOMEM;
+               }
+
+               urb->dev = udev;
+               urb->context = (void*)cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = W9968CF_ISO_PACKETS;
+               urb->complete = w9968cf_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = p_size*j;
+                       urb->iso_frame_desc[j].length = p_size;
+               }
+       }
+
+       /* Transfer size per frame, in WORD ! */
+       d = cam->hw_depth;
+       w = cam->hw_width;
+       h = cam->hw_height;
+
+       t_size = (w*h*d)/16;
+
+       err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
+       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
+
+       /* Transfer size */
+       err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
+       err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
+
+       if (cam->vpp_flag & VPP_DECOMPRESSION)
+               err += w9968cf_upload_quantizationtables(cam);
+
+       vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
+       err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
+
+       err += usb_set_interface(udev, 0, cam->altsetting);
+       err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
+
+       if (err || (vidcapt < 0)) {
+               for (i = 0; i < W9968CF_URBS; i++)
+                       usb_free_urb(cam->urb[i]);
+               DBG(1, "Couldn't tell the camera to start the data transfer")
+               return err;
+       }
+
+       w9968cf_init_framelist(cam);
+
+       /* Begin to grab into the temporary buffer */
+       cam->frame_tmp.status = F_UNUSED;
+       cam->frame_tmp.queued = 0;
+       cam->frame_current = &cam->frame_tmp;
+
+       if (!(cam->vpp_flag & VPP_DECOMPRESSION))
+               DBG(5, "Isochronous transfer size: %lu bytes/frame",
+                   (unsigned long)t_size*2)
+
+       DBG(5, "Starting the isochronous transfer...")
+
+       cam->streaming = 1;
+
+       /* Submit the URBs */
+       for (i = 0; i < W9968CF_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       cam->streaming = 0;
+                       for (j = i-1; j >= 0; j--) {
+                               usb_kill_urb(cam->urb[j]);
+                               usb_free_urb(cam->urb[j]);
+                       }
+                       DBG(1, "Couldn't send a transfer request to the "
+                              "USB core (error #%d, %s)", err,
+                           symbolic(urb_errlist, err))
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_stop_transfer(struct w9968cf_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       unsigned long lock_flags;
+       int err = 0;
+       s8 i;
+
+       if (!cam->streaming)
+               return 0;
+
+       /* This avoids race conditions with usb_submit_urb()
+          in the URB completition handler */
+       spin_lock_irqsave(&cam->urb_lock, lock_flags);
+       cam->streaming = 0;
+       spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
+
+       for (i = W9968CF_URBS-1; i >= 0; i--)
+               if (cam->urb[i]) {
+                       usb_kill_urb(cam->urb[i]);
+                       usb_free_urb(cam->urb[i]);
+                       cam->urb[i] = NULL;
+               }
+
+       if (cam->disconnected)
+               goto exit;
+
+       err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
+       err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
+       err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
+
+       if (err) {
+               DBG(2, "Failed to tell the camera to stop the isochronous "
+                      "transfer. However this is not a critical error.")
+               return -EIO;
+       }
+
+exit:
+       DBG(5, "Isochronous transfer stopped")
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write a W9968CF register.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       int res;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+                             value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
+
+       if (res < 0)
+               DBG(4, "Failed to write a register "
+                      "(value 0x%04X, index 0x%02X, error #%d, %s)",
+                   value, index, res, symbolic(urb_errlist, res))
+
+       return (res >= 0) ? 0 : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read a W9968CF register.
+  Return the register value on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u16* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
+
+       if (res < 0)
+               DBG(4, "Failed to read a register "
+                      "(index 0x%02X, error #%d, %s)",
+                   index, res, symbolic(urb_errlist, res))
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write 64-bit data to the fast serial bus registers.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
+{
+       struct usb_device* udev = cam->usbdev;
+       u16 value;
+       int res;
+
+       value = *data++;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+                             value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
+
+       if (res < 0)
+               DBG(4, "Failed to write the FSB registers "
+                      "(error #%d, %s)", res, symbolic(urb_errlist, res))
+
+       return (res >= 0) ? 0 : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write data to the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
+{
+       int err = 0;
+
+       err = w9968cf_write_reg(cam, value, 0x01);
+       udelay(W9968CF_I2C_BUS_DELAY);
+
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read data from the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_sb(struct w9968cf_device* cam)
+{
+       int v = 0;
+
+       v = w9968cf_read_reg(cam, 0x01);
+       udelay(W9968CF_I2C_BUS_DELAY);
+
+       return v;
+}
+
+
+/*--------------------------------------------------------------------------
+  Upload quantization tables for the JPEG compression.
+  This function is called by w9968cf_start_transfer().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
+{
+       u16 a, b;
+       int err = 0, i, j;
+
+       err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
+
+       for (i = 0, j = 0; i < 32; i++, j += 2) {
+               a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
+               b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
+               err += w9968cf_write_reg(cam, a, 0x40+i);
+               err += w9968cf_write_reg(cam, b, 0x60+i);
+       }
+       err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
+
+       return err;
+}
+
+
+
+/****************************************************************************
+ * Low-level I2C I/O functions.                                             *
+ * The adapter supports the following I2C transfer functions:               *
+ * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
+ * i2c_adap_read_byte_data()                                                *
+ * i2c_adap_read_byte()                                                     *
+ ****************************************************************************/
+
+static int w9968cf_smbus_start(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+       return err;
+}
+
+
+static int w9968cf_smbus_stop(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+
+       return err;
+}
+
+
+static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
+{
+       u8 bit;
+       int err = 0, sda;
+
+       for (bit = 0 ; bit < 8 ; bit++) {
+               sda = (v & 0x80) ? 2 : 0;
+               v <<= 1;
+               /* SDE=1, SDA=sda, SCL=0 */
+               err += w9968cf_write_sb(cam, 0x10 | sda);
+               /* SDE=1, SDA=sda, SCL=1 */
+               err += w9968cf_write_sb(cam, 0x11 | sda);
+               /* SDE=1, SDA=sda, SCL=0 */
+               err += w9968cf_write_sb(cam, 0x10 | sda);
+       }
+
+       return err;
+}
+
+
+static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
+{
+       u8 bit;
+       int err = 0;
+
+       *v = 0;
+       for (bit = 0 ; bit < 8 ; bit++) {
+               *v <<= 1;
+               err += w9968cf_write_sb(cam, 0x0013);
+               *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
+               err += w9968cf_write_sb(cam, 0x0012);
+       }
+
+       return err;
+}
+
+
+static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+       return err;
+}
+
+
+static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
+{
+       int err = 0, sda;
+
+       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+       sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
+       err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+       if (sda < 0)
+               err += sda;
+       if (sda == 1) {
+               DBG(6, "Couldn't receive the ACK")
+               err += -1;
+       }
+
+       return err;
+}
+
+
+/* This seems to refresh the communication through the serial bus */
+static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
+{
+       int err = 0, j;
+
+       for (j = 1; j <= 10; j++) {
+               err = w9968cf_write_reg(cam, 0x0020, 0x01);
+               err += w9968cf_write_reg(cam, 0x0000, 0x01);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
+static int
+w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
+                                    u16 address, u8 subaddress,u8 value)
+{
+       u16* data = cam->data_buffer;
+       int err = 0;
+
+       err += w9968cf_smbus_refresh_bus(cam);
+
+       /* Enable SBUS outputs */
+       err += w9968cf_write_sb(cam, 0x0020);
+
+       data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
+       data[0] |= (address & 0x40) ? 0x4000 : 0x0;
+       data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
+       data[1] |= (address & 0x20) ? 0x0150 : 0x0;
+       data[1] |= (address & 0x10) ? 0x5400 : 0x0;
+       data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
+       data[2] |= (address & 0x04) ? 0x0540 : 0x0;
+       data[2] |= (address & 0x02) ? 0x5000 : 0x0;
+       data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
+       data[3] |= (address & 0x01) ? 0x0054 : 0x0;
+
+       err += w9968cf_write_fsb(cam, data);
+
+       data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
+       data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
+       data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
+       data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
+       data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
+       data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
+       data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
+       data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
+       data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
+       data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
+       data[3] = 0x001d;
+
+       err += w9968cf_write_fsb(cam, data);
+
+       data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
+       data[0] |= (value & 0x40) ? 0x0540 : 0x0;
+       data[0] |= (value & 0x20) ? 0x5000 : 0x0;
+       data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
+       data[1] |= (value & 0x10) ? 0x0054 : 0x0;
+       data[1] |= (value & 0x08) ? 0x1500 : 0x0;
+       data[1] |= (value & 0x04) ? 0x4000 : 0x0;
+       data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
+       data[2] |= (value & 0x02) ? 0x0150 : 0x0;
+       data[2] |= (value & 0x01) ? 0x5400 : 0x0;
+       data[3] = 0xfe1d;
+
+       err += w9968cf_write_fsb(cam, data);
+
+       /* Disable SBUS outputs */
+       err += w9968cf_write_sb(cam, 0x0000);
+
+       if (!err)
+               DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
+                      "value 0x%02X", address, subaddress, value)
+       else
+               DBG(5, "I2C write byte data failed, addr.0x%04X, "
+                      "subaddr.0x%02X, value 0x%02X",
+                   address, subaddress, value)
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
+static int
+w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam,
+                               u16 address, u8 subaddress,
+                               u8* value)
+{
+       int err = 0;
+
+       /* Serial data enable */
+       err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
+
+       err += w9968cf_smbus_start(cam);
+       err += w9968cf_smbus_write_byte(cam, address);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_write_byte(cam, subaddress);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_stop(cam);
+       err += w9968cf_smbus_start(cam);
+       err += w9968cf_smbus_write_byte(cam, address + 1);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_read_byte(cam, value);
+       err += w9968cf_smbus_write_ack(cam);
+       err += w9968cf_smbus_stop(cam);
+
+       /* Serial data disable */
+       err += w9968cf_write_sb(cam, 0x0000);
+
+       if (!err)
+               DBG(5, "I2C read byte data done, addr.0x%04X, "
+                      "subaddr.0x%02X, value 0x%02X",
+                   address, subaddress, *value)
+       else
+               DBG(5, "I2C read byte data failed, addr.0x%04X, "
+                      "subaddr.0x%02X, wrong value 0x%02X",
+                   address, subaddress, *value)
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
+static int
+w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
+                          u16 address, u8* value)
+{
+       int err = 0;
+
+       /* Serial data enable */
+       err += w9968cf_write_sb(cam, 0x0013);
+
+       err += w9968cf_smbus_start(cam);
+       err += w9968cf_smbus_write_byte(cam, address + 1);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_read_byte(cam, value);
+       err += w9968cf_smbus_write_ack(cam);
+       err += w9968cf_smbus_stop(cam);
+
+       /* Serial data disable */
+       err += w9968cf_write_sb(cam, 0x0000);
+
+       if (!err)
+               DBG(5, "I2C read byte done, addr.0x%04X, "
+                      "value 0x%02X", address, *value)
+       else
+               DBG(5, "I2C read byte failed, addr.0x%04X, "
+                      "wrong value 0x%02X", address, *value)
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Value [A] P */
+static int
+w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
+                           u16 address, u8 value)
+{
+       DBG(4, "i2c_write_byte() is an unsupported transfer mode")
+       return -EINVAL;
+}
+
+
+
+/****************************************************************************
+ * I2C interface to kernel                                                  *
+ ****************************************************************************/
+
+static int
+w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+                      unsigned short flags, char read_write, u8 command,
+                      int size, union i2c_smbus_data *data)
+{
+       struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+       u8 i;
+       int err = 0;
+
+       switch (addr) {
+               case OV6xx0_SID:
+               case OV7xx0_SID:
+                       break;
+               default:
+                       DBG(4, "Rejected slave ID 0x%04X", addr)
+                       return -EINVAL;
+       }
+
+       if (size == I2C_SMBUS_BYTE) {
+               /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
+               addr <<= 1;
+
+               if (read_write == I2C_SMBUS_WRITE)
+                       err = w9968cf_i2c_adap_write_byte(cam, addr, command);
+               else if (read_write == I2C_SMBUS_READ)
+                       err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
+
+       } else if (size == I2C_SMBUS_BYTE_DATA) {
+               addr <<= 1;
+
+               if (read_write == I2C_SMBUS_WRITE)
+                       err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
+                                                         command, data->byte);
+               else if (read_write == I2C_SMBUS_READ) {
+                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+                               err = w9968cf_i2c_adap_read_byte_data(cam,addr,
+                                                        command, &data->byte);
+                               if (err) {
+                                       if (w9968cf_smbus_refresh_bus(cam)) {
+                                               err = -EIO;
+                                               break;
+                                       }
+                               } else
+                                       break;
+                       }
+
+               } else
+                       return -EINVAL;
+
+       } else {
+               DBG(4, "Unsupported I2C transfer mode (%d)", size)
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+
+static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
+{
+       return I2C_FUNC_SMBUS_READ_BYTE |
+              I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+
+static int w9968cf_i2c_attach_inform(struct i2c_client* client)
+{
+       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
+       int id = client->driver->id, err = 0;
+
+       if (id == I2C_DRIVERID_OVCAMCHIP) {
+               cam->sensor_client = client;
+               err = w9968cf_sensor_init(cam);
+               if (err) {
+                       cam->sensor_client = NULL;
+                       return err;
+               }
+       } else {
+               DBG(4, "Rejected client [%s] with driver [%s]",
+                   client->name, client->driver->driver.name)
+               return -EINVAL;
+       }
+
+       DBG(5, "I2C attach client [%s] with driver [%s]",
+           client->name, client->driver->driver.name)
+
+       return 0;
+}
+
+
+static int w9968cf_i2c_detach_inform(struct i2c_client* client)
+{
+       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
+
+       if (cam->sensor_client == client)
+               cam->sensor_client = NULL;
+
+       DBG(5, "I2C detach client [%s]", client->name)
+
+       return 0;
+}
+
+
+static int
+w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
+                   unsigned long arg)
+{
+       return 0;
+}
+
+
+static int w9968cf_i2c_init(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       static struct i2c_algorithm algo = {
+               .smbus_xfer =    w9968cf_i2c_smbus_xfer,
+               .algo_control =  w9968cf_i2c_control,
+               .functionality = w9968cf_i2c_func,
+       };
+
+       static struct i2c_adapter adap = {
+               .id =                I2C_HW_SMBUS_W9968CF,
+               .class =             I2C_CLASS_CAM_DIGITAL,
+               .owner =             THIS_MODULE,
+               .client_register =   w9968cf_i2c_attach_inform,
+               .client_unregister = w9968cf_i2c_detach_inform,
+               .algo =              &algo,
+       };
+
+       memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
+       strcpy(cam->i2c_adapter.name, "w9968cf");
+       i2c_set_adapdata(&cam->i2c_adapter, cam);
+
+       DBG(6, "Registering I2C adapter with kernel...")
+
+       err = i2c_add_adapter(&cam->i2c_adapter);
+       if (err)
+               DBG(1, "Failed to register the I2C adapter")
+       else
+               DBG(5, "I2C adapter registered")
+
+       return err;
+}
+
+
+
+/****************************************************************************
+ * Helper functions                                                         *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  Turn on the LED on some webcams. A beep should be heard too.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_turn_on_led(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
+       err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
+       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
+       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
+       err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
+       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
+
+       if (err)
+               DBG(2, "Couldn't turn on the LED")
+
+       DBG(5, "LED turned on")
+
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write some registers for the device initialization.
+  This function is called once on open().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_init_chip(struct w9968cf_device* cam)
+{
+       unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
+                     y0 = 0x0000,
+                     u0 = y0 + hw_bufsize/2,
+                     v0 = u0 + hw_bufsize/4,
+                     y1 = v0 + hw_bufsize/4,
+                     u1 = y1 + hw_bufsize/2,
+                     v1 = u1 + hw_bufsize/4;
+       int err = 0;
+
+       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
+       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
+
+       err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
+       err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
+
+       err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
+       err += w9968cf_write_reg(cam, y0 >> 16, 0x21);    /* Y buf.0, high */
+       err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
+       err += w9968cf_write_reg(cam, u0 >> 16, 0x25);    /* U buf.0, high */
+       err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
+       err += w9968cf_write_reg(cam, v0 >> 16, 0x29);    /* V buf.0, high */
+
+       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
+       err += w9968cf_write_reg(cam, y1 >> 16, 0x23);    /* Y buf.1, high */
+       err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
+       err += w9968cf_write_reg(cam, u1 >> 16, 0x27);    /* U buf.1, high */
+       err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
+       err += w9968cf_write_reg(cam, v1 >> 16, 0x2b);    /* V buf.1, high */
+
+       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
+       err += w9968cf_write_reg(cam, y1 >> 16, 0x33);    /* JPEG buf 0 high */
+
+       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
+       err += w9968cf_write_reg(cam, y1 >> 16, 0x35);    /* JPEG bug 1 high */
+
+       err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
+       err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
+       err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
+       err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
+
+       err += w9968cf_set_picture(cam, cam->picture); /* this before */
+       err += w9968cf_set_window(cam, cam->window);
+
+       if (err)
+               DBG(1, "Chip initialization failed")
+       else
+               DBG(5, "Chip successfully initialized")
+
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return non-zero if the palette is supported, 0 otherwise.
+  --------------------------------------------------------------------------*/
+static inline u16 w9968cf_valid_palette(u16 palette)
+{
+       u8 i = 0;
+       while (w9968cf_formatlist[i].palette != 0) {
+               if (palette == w9968cf_formatlist[i].palette)
+                       return palette;
+               i++;
+       }
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return the depth corresponding to the given palette.
+  Palette _must_ be supported !
+  --------------------------------------------------------------------------*/
+static inline u16 w9968cf_valid_depth(u16 palette)
+{
+       u8 i=0;
+       while (w9968cf_formatlist[i].palette != palette)
+               i++;
+
+       return w9968cf_formatlist[i].depth;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return non-zero if the format requires decompression, 0 otherwise.
+  --------------------------------------------------------------------------*/
+static inline u8 w9968cf_need_decompression(u16 palette)
+{
+       u8 i = 0;
+       while (w9968cf_formatlist[i].palette != 0) {
+               if (palette == w9968cf_formatlist[i].palette)
+                       return w9968cf_formatlist[i].compression;
+               i++;
+       }
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change the picture settings of the camera.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
+{
+       u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
+       int err = 0;
+
+       /* Make sure we are using a valid depth */
+       pict.depth = w9968cf_valid_depth(pict.palette);
+
+       fmt = pict.palette;
+
+       hw_depth = pict.depth; /* depth used by the winbond chip */
+       hw_palette = pict.palette; /* palette used by the winbond chip */
+
+       /* VS & HS polarities */
+       reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
+
+       switch (fmt)
+       {
+               case VIDEO_PALETTE_UYVY:
+                       reg_v |= 0x0000;
+                       cam->vpp_flag = VPP_NONE;
+                       break;
+               case VIDEO_PALETTE_YUV422P:
+                       reg_v |= 0x0002;
+                       cam->vpp_flag = VPP_DECOMPRESSION;
+                       break;
+               case VIDEO_PALETTE_YUV420:
+               case VIDEO_PALETTE_YUV420P:
+                       reg_v |= 0x0003;
+                       cam->vpp_flag = VPP_DECOMPRESSION;
+                       break;
+               case VIDEO_PALETTE_YUYV:
+               case VIDEO_PALETTE_YUV422:
+                       reg_v |= 0x0000;
+                       cam->vpp_flag = VPP_SWAP_YUV_BYTES;
+                       hw_palette = VIDEO_PALETTE_UYVY;
+                       break;
+               /* Original video is used instead of RGBX palettes.
+                  Software conversion later. */
+               case VIDEO_PALETTE_GREY:
+               case VIDEO_PALETTE_RGB555:
+               case VIDEO_PALETTE_RGB565:
+               case VIDEO_PALETTE_RGB24:
+               case VIDEO_PALETTE_RGB32:
+                       reg_v |= 0x0000; /* UYVY 16 bit is used */
+                       hw_depth = 16;
+                       hw_palette = VIDEO_PALETTE_UYVY;
+                       cam->vpp_flag = VPP_UYVY_TO_RGBX;
+                       break;
+       }
+
+       /* NOTE: due to memory issues, it is better to disable the hardware
+                double buffering during compression */
+       if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
+               reg_v |= 0x0080;
+
+       if (cam->clamping)
+               reg_v |= 0x0020;
+
+       if (cam->filter_type == 1)
+               reg_v |= 0x0008;
+       else if (cam->filter_type == 2)
+               reg_v |= 0x000c;
+
+       if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
+               goto error;
+
+       if ((err = w9968cf_sensor_update_picture(cam, pict)))
+               goto error;
+
+       /* If all went well, update the device data structure */
+       memcpy(&cam->picture, &pict, sizeof(pict));
+       cam->hw_depth = hw_depth;
+       cam->hw_palette = hw_palette;
+
+       /* Settings changed, so we clear the frame buffers */
+       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
+
+       DBG(4, "Palette is %s, depth is %u bpp",
+           symbolic(v4l1_plist, pict.palette), pict.depth)
+
+       return 0;
+
+error:
+       DBG(1, "Failed to change picture settings")
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change the capture area size of the camera.
+  This function _must_ be called _after_ w9968cf_set_picture().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
+{
+       u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
+       unsigned long fw, fh;
+       struct ovcamchip_window s_win;
+       int err = 0;
+
+       /* Work around to avoid FP arithmetics */
+       #define __SC(x) ((x) << 10)
+       #define __UNSC(x) ((x) >> 10)
+
+       /* Make sure we are using a supported resolution */
+       if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
+                                             (u16*)&win.height)))
+               goto error;
+
+       /* Scaling factors */
+       fw = __SC(win.width) / cam->maxwidth;
+       fh = __SC(win.height) / cam->maxheight;
+
+       /* Set up the width and height values used by the chip */
+       if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
+               cam->vpp_flag |= VPP_UPSCALE;
+               /* Calculate largest w,h mantaining the same w/h ratio */
+               w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
+               h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+               if (w < cam->minwidth) /* just in case */
+                       w = cam->minwidth;
+               if (h < cam->minheight) /* just in case */
+                       h = cam->minheight;
+       } else {
+               cam->vpp_flag &= ~VPP_UPSCALE;
+               w = win.width;
+               h = win.height;
+       }
+
+       /* x,y offsets of the cropped area */
+       scx = cam->start_cropx;
+       scy = cam->start_cropy;
+
+       /* Calculate cropped area manteining the right w/h ratio */
+       if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
+               cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
+               ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+       } else {
+               cw = w;
+               ch = h;
+       }
+
+       /* Setup the window of the sensor */
+       s_win.format = VIDEO_PALETTE_UYVY;
+       s_win.width = cam->maxwidth;
+       s_win.height = cam->maxheight;
+       s_win.quarter = 0; /* full progressive video */
+
+       /* Center it */
+       s_win.x = (s_win.width - cw) / 2;
+       s_win.y = (s_win.height - ch) / 2;
+
+       /* Clock divisor */
+       if (cam->clockdiv >= 0)
+               s_win.clockdiv = cam->clockdiv; /* manual override */
+       else
+               switch (cam->sensor) {
+                       case CC_OV6620:
+                               s_win.clockdiv = 0;
+                               break;
+                       case CC_OV6630:
+                               s_win.clockdiv = 0;
+                               break;
+                       case CC_OV76BE:
+                       case CC_OV7610:
+                       case CC_OV7620:
+                               s_win.clockdiv = 0;
+                               break;
+                       default:
+                               s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
+               }
+
+       /* We have to scale win.x and win.y offsets */
+       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
+            || (cam->vpp_flag & VPP_UPSCALE) ) {
+               ax = __SC(win.x)/fw;
+               ay = __SC(win.y)/fh;
+       } else {
+               ax = win.x;
+               ay = win.y;
+       }
+
+       if ((ax + cw) > cam->maxwidth)
+               ax = cam->maxwidth - cw;
+
+       if ((ay + ch) > cam->maxheight)
+               ay = cam->maxheight - ch;
+
+       /* Adjust win.x, win.y */
+       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
+            || (cam->vpp_flag & VPP_UPSCALE) ) {
+               win.x = __UNSC(ax*fw);
+               win.y = __UNSC(ay*fh);
+       } else {
+               win.x = ax;
+               win.y = ay;
+       }
+
+       /* Offsets used by the chip */
+       x = ax + s_win.x;
+       y = ay + s_win.y;
+
+       /* Go ! */
+       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
+               goto error;
+
+       err += w9968cf_write_reg(cam, scx + x, 0x10);
+       err += w9968cf_write_reg(cam, scy + y, 0x11);
+       err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
+       err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
+       err += w9968cf_write_reg(cam, w, 0x14);
+       err += w9968cf_write_reg(cam, h, 0x15);
+
+       /* JPEG width & height */
+       err += w9968cf_write_reg(cam, w, 0x30);
+       err += w9968cf_write_reg(cam, h, 0x31);
+
+       /* Y & UV frame buffer strides (in WORD) */
+       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+               err += w9968cf_write_reg(cam, w/2, 0x2c);
+               err += w9968cf_write_reg(cam, w/4, 0x2d);
+       } else
+               err += w9968cf_write_reg(cam, w, 0x2c);
+
+       if (err)
+               goto error;
+
+       /* If all went well, update the device data structure */
+       memcpy(&cam->window, &win, sizeof(win));
+       cam->hw_width = w;
+       cam->hw_height = h;
+
+       /* Settings changed, so we clear the frame buffers */
+       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
+
+       DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)",
+           win.width, win.height, win.x, win.y)
+
+       PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
+             "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
+             x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
+             win.width, win.height)
+
+       return 0;
+
+error:
+       DBG(1, "Failed to change the capture area size")
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Adjust the asked values for window width and height.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
+{
+       u16 maxw, maxh;
+
+       if ((*width < cam->minwidth) || (*height < cam->minheight))
+               return -ERANGE;
+
+       maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
+              w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
+                          : cam->maxwidth;
+       maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
+              w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
+                          : cam->maxheight;
+
+       if (*width > maxw)
+               *width = maxw;
+       if (*height > maxh)
+               *height = maxh;
+
+       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+               *width  &= ~15L; /* multiple of 16 */
+               *height &= ~15L;
+       }
+
+       PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Initialize the FIFO list of requested frames.
+  --------------------------------------------------------------------------*/
+static void w9968cf_init_framelist(struct w9968cf_device* cam)
+{
+       u8 i;
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->requested_frame[i] = NULL;
+               cam->frame[i].queued = 0;
+               cam->frame[i].status = F_UNUSED;
+       }
+}
+
+
+/*--------------------------------------------------------------------------
+  Add a frame in the FIFO list of requested frames.
+  This function is called in process context.
+  --------------------------------------------------------------------------*/
+static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
+{
+       u8 f;
+       unsigned long lock_flags;
+
+       spin_lock_irqsave(&cam->flist_lock, lock_flags);
+
+       for (f=0; cam->requested_frame[f] != NULL; f++);
+       cam->requested_frame[f] = &cam->frame[f_num];
+       cam->frame[f_num].queued = 1;
+       cam->frame[f_num].status = F_UNUSED; /* clear the status */
+
+       spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
+
+       DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
+}
+
+
+/*--------------------------------------------------------------------------
+  Read, store and remove the first pointer in the FIFO list of requested
+  frames. This function is called in interrupt context.
+  --------------------------------------------------------------------------*/
+static void
+w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
+{
+       u8 i;
+
+       spin_lock(&cam->flist_lock);
+
+       *framep = cam->requested_frame[0];
+
+       /* Shift the list of pointers */
+       for (i = 0; i < cam->nbuffers-1; i++)
+               cam->requested_frame[i] = cam->requested_frame[i+1];
+       cam->requested_frame[i] = NULL;
+
+       spin_unlock(&cam->flist_lock);
+
+       DBG(6,"Popped frame #%d from the list", (*framep)->number)
+}
+
+
+/*--------------------------------------------------------------------------
+  High-level video post-processing routine on grabbed frames.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_postprocess_frame(struct w9968cf_device* cam,
+                         struct w9968cf_frame_t* fr)
+{
+       void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
+       u16 w = cam->window.width,
+           h = cam->window.height,
+           d = cam->picture.depth,
+           fmt = cam->picture.palette,
+           rgb = cam->force_rgb,
+           hw_w = cam->hw_width,
+           hw_h = cam->hw_height,
+           hw_d = cam->hw_depth;
+       int err = 0;
+
+       #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
+
+       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+               memcpy(pOut, pIn, fr->length);
+               _PSWAP(pIn, pOut)
+               err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
+               PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
+               fr->length = (hw_w*hw_h*hw_d)/8;
+               _PSWAP(pIn, pOut)
+               if (err) {
+                       DBG(4, "An error occurred while decoding the frame: "
+                              "%s", symbolic(decoder_errlist, err))
+                       return err;
+               } else
+                       DBG(6, "Frame decoded")
+       }
+
+       if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
+               w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
+               DBG(6, "Original UYVY component ordering changed")
+       }
+
+       if (cam->vpp_flag & VPP_UPSCALE) {
+               w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
+               fr->length = (w*h*hw_d)/8;
+               _PSWAP(pIn, pOut)
+               DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
+                   hw_w, hw_h, hw_d, w, h)
+       }
+
+       if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
+               w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
+               fr->length = (w*h*d)/8;
+               _PSWAP(pIn, pOut)
+               DBG(6, "UYVY-16bit to %s conversion done",
+                   symbolic(v4l1_plist, fmt))
+       }
+
+       if (pOut == fr->buffer)
+               memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
+
+       return 0;
+}
+
+
+
+/****************************************************************************
+ * Image sensor control routines                                            *
+ ****************************************************************************/
+
+static int
+w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
+{
+       struct ovcamchip_control ctl;
+       int err;
+
+       ctl.id = cid;
+       ctl.value = val;
+
+       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
+
+       return err;
+}
+
+
+static int
+w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
+{
+       struct ovcamchip_control ctl;
+       int err;
+
+       ctl.id = cid;
+
+       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
+       if (!err)
+               *val = ctl.value;
+
+       return err;
+}
+
+
+static int
+w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
+{
+       struct i2c_client* c = cam->sensor_client;
+       int rc = 0;
+
+       if (!c || !c->driver || !c->driver->command)
+               return -EINVAL;
+
+       rc = c->driver->command(c, cmd, arg);
+       /* The I2C driver returns -EPERM on non-supported controls */
+       return (rc < 0 && rc != -EPERM) ? rc : 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Update some settings of the image sensor.
+  Returns: 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       /* Auto brightness */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT,
+                                        cam->auto_brt);
+       if (err)
+               return err;
+
+       /* Auto exposure */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP,
+                                        cam->auto_exp);
+       if (err)
+               return err;
+
+       /* Banding filter */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT,
+                                        cam->bandfilt);
+       if (err)
+               return err;
+
+       /* Light frequency */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
+                                        cam->lightfreq);
+       if (err)
+               return err;
+
+       /* Back light */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
+                                        cam->backlight);
+       if (err)
+               return err;
+
+       /* Mirror */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
+                                        cam->mirror);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Get some current picture settings from the image sensor and update the
+  internal 'picture' structure of the camera.
+  Returns: 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
+{
+       int err, v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
+       if (err)
+               return err;
+       cam->picture.contrast = v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
+       if (err)
+               return err;
+       cam->picture.brightness = v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
+       if (err)
+               return err;
+       cam->picture.colour = v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
+       if (err)
+               return err;
+       cam->picture.hue = v;
+
+       DBG(5, "Got picture settings from the image sensor")
+
+       PDBGG("Brightness, contrast, hue, colour, whiteness are "
+             "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
+             cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Update picture settings of the image sensor.
+  Returns: 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_sensor_update_picture(struct w9968cf_device* cam,
+                             struct video_picture pict)
+{
+       int err = 0;
+
+       if ((!cam->sensor_initialized)
+           || pict.contrast != cam->picture.contrast) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
+                                                pict.contrast);
+               if (err)
+                       goto fail;
+               DBG(4, "Contrast changed from %u to %u",
+                   cam->picture.contrast, pict.contrast)
+               cam->picture.contrast = pict.contrast;
+       }
+
+       if (((!cam->sensor_initialized) ||
+           pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT,
+                                                pict.brightness);
+               if (err)
+                       goto fail;
+               DBG(4, "Brightness changed from %u to %u",
+                   cam->picture.brightness, pict.brightness)
+               cam->picture.brightness = pict.brightness;
+       }
+
+       if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT,
+                                                pict.colour);
+               if (err)
+                       goto fail;
+               DBG(4, "Colour changed from %u to %u",
+                   cam->picture.colour, pict.colour)
+               cam->picture.colour = pict.colour;
+       }
+
+       if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE,
+                                                pict.hue);
+               if (err)
+                       goto fail;
+               DBG(4, "Hue changed from %u to %u",
+                   cam->picture.hue, pict.hue)
+               cam->picture.hue = pict.hue;
+       }
+
+       return 0;
+
+fail:
+       DBG(4, "Failed to change sensor picture setting")
+       return err;
+}
+
+
+
+/****************************************************************************
+ * Camera configuration                                                     *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  This function is called when a supported image sensor is detected.
+  Return 0 if the initialization succeeds, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_init(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE,
+                                     &cam->monochrome)))
+               goto error;
+
+       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE,
+                                     &cam->sensor)))
+               goto error;
+
+       /* NOTE: Make sure width and height are a multiple of 16 */
+       switch (cam->sensor_client->addr) {
+               case OV6xx0_SID:
+                       cam->maxwidth = 352;
+                       cam->maxheight = 288;
+                       cam->minwidth = 64;
+                       cam->minheight = 48;
+                       break;
+               case OV7xx0_SID:
+                       cam->maxwidth = 640;
+                       cam->maxheight = 480;
+                       cam->minwidth = 64;
+                       cam->minheight = 48;
+                       break;
+               default:
+                       DBG(1, "Not supported image sensor detected for %s",
+                           symbolic(camlist, cam->id))
+                       return -EINVAL;
+       }
+
+       /* These values depend on the ones in the ovxxx0.c sources */
+       switch (cam->sensor) {
+               case CC_OV7620:
+                       cam->start_cropx = 287;
+                       cam->start_cropy = 35;
+                       /* Seems to work around a bug in the image sensor */
+                       cam->vs_polarity = 1;
+                       cam->hs_polarity = 1;
+                       break;
+               default:
+                       cam->start_cropx = 320;
+                       cam->start_cropy = 35;
+                       cam->vs_polarity = 1;
+                       cam->hs_polarity = 0;
+       }
+
+       if ((err = w9968cf_sensor_update_settings(cam)))
+               goto error;
+
+       if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
+               goto error;
+
+       cam->sensor_initialized = 1;
+
+       DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
+       return 0;
+
+error:
+       cam->sensor_initialized = 0;
+       cam->sensor = CC_UNKNOWN;
+       DBG(1, "Image sensor initialization failed for %s (/dev/video%d). "
+              "Try to detach and attach this device again",
+           symbolic(camlist, cam->id), cam->v4ldev->minor)
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Fill some basic fields in the main device data structure.
+  This function is called once on w9968cf_usb_probe() for each recognized
+  camera.
+  --------------------------------------------------------------------------*/
+static void
+w9968cf_configure_camera(struct w9968cf_device* cam,
+                        struct usb_device* udev,
+                        enum w9968cf_model_id mod_id,
+                        const unsigned short dev_nr)
+{
+       mutex_init(&cam->fileop_mutex);
+       init_waitqueue_head(&cam->open);
+       spin_lock_init(&cam->urb_lock);
+       spin_lock_init(&cam->flist_lock);
+
+       cam->users = 0;
+       cam->disconnected = 0;
+       cam->id = mod_id;
+       cam->sensor = CC_UNKNOWN;
+       cam->sensor_initialized = 0;
+
+       /* Calculate the alternate setting number (from 1 to 16)
+          according to the 'packet_size' module parameter */
+       if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
+               packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
+       for (cam->altsetting = 1;
+            packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
+            cam->altsetting++);
+
+       cam->max_buffers = (max_buffers[dev_nr] < 2 ||
+                           max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
+                          ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
+
+       cam->double_buffer = (double_buffer[dev_nr] == 0 ||
+                             double_buffer[dev_nr] == 1)
+                            ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
+
+       cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
+                       ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
+
+       cam->filter_type = (filter_type[dev_nr] == 0 ||
+                           filter_type[dev_nr] == 1 ||
+                           filter_type[dev_nr] == 2)
+                          ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
+
+       cam->capture = 1;
+
+       cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
+                        ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
+
+       cam->decompression = (decompression[dev_nr] == 0 ||
+                             decompression[dev_nr] == 1 ||
+                             decompression[dev_nr] == 2)
+                            ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
+
+       cam->upscaling = (upscaling[dev_nr] == 0 ||
+                         upscaling[dev_nr] == 1)
+                        ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
+
+       cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
+                       ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
+
+       cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
+                       ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
+
+       cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
+                        ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
+
+       cam->bandfilt = (bandingfilter[dev_nr] == 0 ||
+                        bandingfilter[dev_nr] == 1)
+                       ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
+
+       cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
+                        ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
+
+       cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
+                       ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
+
+       cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
+                     ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
+
+       cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
+                         ? monochrome[dev_nr] : W9968CF_MONOCHROME;
+
+       cam->picture.brightness = (u16)brightness[dev_nr];
+       cam->picture.hue = (u16)hue[dev_nr];
+       cam->picture.colour = (u16)colour[dev_nr];
+       cam->picture.contrast = (u16)contrast[dev_nr];
+       cam->picture.whiteness = (u16)whiteness[dev_nr];
+       if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
+               cam->picture.palette = (u16)force_palette[dev_nr];
+               cam->force_palette = 1;
+       } else {
+               cam->force_palette = 0;
+               if (cam->decompression == 0)
+                       cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
+               else if (cam->decompression == 1)
+                       cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
+               else
+                       cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
+       }
+       cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
+
+       cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
+                        ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
+
+       cam->window.x = 0;
+       cam->window.y = 0;
+       cam->window.width = W9968CF_WIDTH;
+       cam->window.height = W9968CF_HEIGHT;
+       cam->window.chromakey = 0;
+       cam->window.clipcount = 0;
+       cam->window.flags = 0;
+
+       DBG(3, "%s configured with settings #%u:",
+           symbolic(camlist, cam->id), dev_nr)
+
+       DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
+           wMaxPacketSize[cam->altsetting-1])
+
+       DBG(3, "- Number of requested video frame buffers: %u",
+           cam->max_buffers)
+
+       if (cam->double_buffer)
+               DBG(3, "- Hardware double buffering enabled")
+       else
+               DBG(3, "- Hardware double buffering disabled")
+
+       if (cam->filter_type == 0)
+               DBG(3, "- Video filtering disabled")
+       else if (cam->filter_type == 1)
+               DBG(3, "- Video filtering enabled: type 1-2-1")
+       else if (cam->filter_type == 2)
+               DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
+
+       if (cam->clamping)
+               DBG(3, "- Video data clamping (CCIR-601 format) enabled")
+       else
+               DBG(3, "- Video data clamping (CCIR-601 format) disabled")
+
+       if (cam->largeview)
+               DBG(3, "- Large view enabled")
+       else
+               DBG(3, "- Large view disabled")
+
+       if ((cam->decompression) == 0 && (!cam->force_palette))
+               DBG(3, "- Decompression disabled")
+       else if ((cam->decompression) == 1 && (!cam->force_palette))
+               DBG(3, "- Decompression forced")
+       else if ((cam->decompression) == 2 && (!cam->force_palette))
+               DBG(3, "- Decompression allowed")
+
+       if (cam->upscaling)
+               DBG(3, "- Software image scaling enabled")
+       else
+               DBG(3, "- Software image scaling disabled")
+
+       if (cam->force_palette)
+               DBG(3, "- Image palette forced to %s",
+                   symbolic(v4l1_plist, cam->picture.palette))
+
+       if (cam->force_rgb)
+               DBG(3, "- RGB component ordering will be used instead of BGR")
+
+       if (cam->auto_brt)
+               DBG(3, "- Auto brightness enabled")
+       else
+               DBG(3, "- Auto brightness disabled")
+
+       if (cam->auto_exp)
+               DBG(3, "- Auto exposure enabled")
+       else
+               DBG(3, "- Auto exposure disabled")
+
+       if (cam->backlight)
+               DBG(3, "- Backlight exposure algorithm enabled")
+       else
+               DBG(3, "- Backlight exposure algorithm disabled")
+
+       if (cam->mirror)
+               DBG(3, "- Mirror enabled")
+       else
+               DBG(3, "- Mirror disabled")
+
+       if (cam->bandfilt)
+               DBG(3, "- Banding filter enabled")
+       else
+               DBG(3, "- Banding filter disabled")
+
+       DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
+
+       if (cam->clockdiv == -1)
+               DBG(3, "- Automatic clock divisor enabled")
+       else
+               DBG(3, "- Clock divisor: %d", cam->clockdiv)
+
+       if (cam->monochrome)
+               DBG(3, "- Image sensor used as monochrome")
+       else
+               DBG(3, "- Image sensor not used as monochrome")
+}
+
+
+/*--------------------------------------------------------------------------
+  If the video post-processing module is not loaded, some parameters
+  must be overridden.
+  --------------------------------------------------------------------------*/
+static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
+{
+       if (!w9968cf_vpp) {
+               if (cam->decompression == 1) {
+                       cam->decompression = 2;
+                       DBG(2, "Video post-processing module not found: "
+                              "'decompression' parameter forced to 2")
+               }
+               if (cam->upscaling) {
+                       cam->upscaling = 0;
+                       DBG(2, "Video post-processing module not found: "
+                              "'upscaling' parameter forced to 0")
+               }
+               if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
+                       cam->force_palette = 0;
+                       DBG(2, "Video post-processing module not found: "
+                              "'force_palette' parameter forced to 0")
+               }
+               cam->picture.palette = VIDEO_PALETTE_UYVY;
+               cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
+       }
+}
+
+
+/*--------------------------------------------------------------------------
+  Release the resources used by the driver.
+  This function is called on disconnect
+  (or on close if deallocation has been deferred)
+  --------------------------------------------------------------------------*/
+static void w9968cf_release_resources(struct w9968cf_device* cam)
+{
+       mutex_lock(&w9968cf_devlist_mutex);
+
+       DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
+
+       video_unregister_device(cam->v4ldev);
+       list_del(&cam->v4llist);
+       i2c_del_adapter(&cam->i2c_adapter);
+       w9968cf_deallocate_memory(cam);
+       kfree(cam->control_buffer);
+       kfree(cam->data_buffer);
+
+       mutex_unlock(&w9968cf_devlist_mutex);
+}
+
+
+
+/****************************************************************************
+ * Video4Linux interface                                                    *
+ ****************************************************************************/
+
+static int w9968cf_open(struct inode* inode, struct file* filp)
+{
+       struct w9968cf_device* cam;
+       int err;
+
+       /* This the only safe way to prevent race conditions with disconnect */
+       if (!down_read_trylock(&w9968cf_disconnect))
+               return -ERESTARTSYS;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex);
+
+       if (cam->sensor == CC_UNKNOWN) {
+               DBG(2, "No supported image sensor has been detected by the "
+                      "'ovcamchip' module for the %s (/dev/video%d). Make "
+                      "sure it is loaded *before* (re)connecting the camera.",
+                   symbolic(camlist, cam->id), cam->v4ldev->minor)
+               mutex_unlock(&cam->dev_mutex);
+               up_read(&w9968cf_disconnect);
+               return -ENODEV;
+       }
+
+       if (cam->users) {
+               DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
+                   symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
+               if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
+                       mutex_unlock(&cam->dev_mutex);
+                       up_read(&w9968cf_disconnect);
+                       return -EWOULDBLOCK;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                        cam->disconnected ||
+                                                        !cam->users);
+               if (err) {
+                       up_read(&w9968cf_disconnect);
+                       return err;
+               }
+               if (cam->disconnected) {
+                       up_read(&w9968cf_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+       DBG(5, "Opening '%s', /dev/video%d ...",
+           symbolic(camlist, cam->id), cam->v4ldev->minor)
+
+       cam->streaming = 0;
+       cam->misconfigured = 0;
+
+       w9968cf_adjust_configuration(cam);
+
+       if ((err = w9968cf_allocate_memory(cam)))
+               goto deallocate_memory;
+
+       if ((err = w9968cf_init_chip(cam)))
+               goto deallocate_memory;
+
+       if ((err = w9968cf_start_transfer(cam)))
+               goto deallocate_memory;
+
+       filp->private_data = cam;
+
+       cam->users++;
+       strcpy(cam->command, current->comm);
+
+       init_waitqueue_head(&cam->wait_queue);
+
+       DBG(5, "Video device is open")
+
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&w9968cf_disconnect);
+
+       return 0;
+
+deallocate_memory:
+       w9968cf_deallocate_memory(cam);
+       DBG(2, "Failed to open the video device")
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&w9968cf_disconnect);
+       return err;
+}
+
+
+static int w9968cf_release(struct inode* inode, struct file* filp)
+{
+       struct w9968cf_device* cam;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       w9968cf_stop_transfer(cam);
+
+       if (cam->disconnected) {
+               w9968cf_release_resources(cam);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       w9968cf_deallocate_memory(cam);
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(5, "Video device closed")
+       mutex_unlock(&cam->dev_mutex);
+       return 0;
+}
+
+
+static ssize_t
+w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct w9968cf_device* cam;
+       struct w9968cf_frame_t* fr;
+       int err = 0;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       if (filp->f_flags & O_NONBLOCK)
+               return -EWOULDBLOCK;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->disconnected) {
+               DBG(2, "Device not present")
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->misconfigured) {
+               DBG(2, "The camera is misconfigured. Close and open it again.")
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (!cam->frame[0].queued)
+               w9968cf_push_frame(cam, 0);
+
+       if (!cam->frame[1].queued)
+               w9968cf_push_frame(cam, 1);
+
+       err = wait_event_interruptible(cam->wait_queue,
+                                      cam->frame[0].status == F_READY ||
+                                      cam->frame[1].status == F_READY ||
+                                      cam->disconnected);
+       if (err) {
+               mutex_unlock(&cam->fileop_mutex);
+               return err;
+       }
+       if (cam->disconnected) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
+
+       if (w9968cf_vpp)
+               w9968cf_postprocess_frame(cam, fr);
+
+       if (count > fr->length)
+               count = fr->length;
+
+       if (copy_to_user(buf, fr->buffer, count)) {
+               fr->status = F_UNUSED;
+               mutex_unlock(&cam->fileop_mutex);
+               return -EFAULT;
+       }
+       *f_pos += count;
+
+       fr->status = F_UNUSED;
+
+       DBG(5, "%zu bytes read", count)
+
+       mutex_unlock(&cam->fileop_mutex);
+       return count;
+}
+
+
+static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct w9968cf_device* cam = (struct w9968cf_device*)
+                                    video_get_drvdata(video_devdata(filp));
+       unsigned long vsize = vma->vm_end - vma->vm_start,
+                     psize = cam->nbuffers * cam->frame[0].size,
+                     start = vma->vm_start,
+                     pos = (unsigned long)cam->frame[0].buffer,
+                     page;
+
+       if (cam->disconnected) {
+               DBG(2, "Device not present")
+               return -ENODEV;
+       }
+
+       if (cam->misconfigured) {
+               DBG(2, "The camera is misconfigured. Close and open it again")
+               return -EIO;
+       }
+
+       PDBGG("mmapping %lu bytes...", vsize)
+
+       if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
+               return -EINVAL;
+
+       while (vsize > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
+                                               PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               vsize -= PAGE_SIZE;
+       }
+
+       DBG(5, "mmap method successfully called")
+       return 0;
+}
+
+
+static int
+w9968cf_ioctl(struct inode* inode, struct file* filp,
+             unsigned int cmd, unsigned long arg)
+{
+       struct w9968cf_device* cam;
+       int err;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->disconnected) {
+               DBG(2, "Device not present")
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->misconfigured) {
+               DBG(2, "The camera is misconfigured. Close and open it again.")
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+       return err;
+}
+
+
+static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
+                            unsigned int cmd, void __user * arg)
+{
+       struct w9968cf_device* cam;
+       const char* v4l1_ioctls[] = {
+               "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
+               "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
+               "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
+               "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
+               "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE",
+               "GVBIFMT", "SVBIFMT"
+       };
+
+       #define V4L1_IOCTL(cmd) \
+               ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
+               v4l1_ioctls[_IOC_NR((cmd))] : "?")
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOCGCAP: /* get video capability */
+       {
+               struct video_capability cap = {
+                       .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
+                       .channels = 1,
+                       .audios = 0,
+                       .minwidth = cam->minwidth,
+                       .minheight = cam->minheight,
+               };
+               sprintf(cap.name, "W996[87]CF USB Camera #%d",
+                       cam->v4ldev->minor);
+               cap.maxwidth = (cam->upscaling && w9968cf_vpp)
+                              ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
+                                : cam->maxwidth;
+               cap.maxheight = (cam->upscaling && w9968cf_vpp)
+                               ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
+                                 : cam->maxheight;
+
+               if (copy_to_user(arg, &cap, sizeof(cap)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGCAP successfully called")
+               return 0;
+       }
+
+       case VIDIOCGCHAN: /* get video channel informations */
+       {
+               struct video_channel chan;
+               if (copy_from_user(&chan, arg, sizeof(chan)))
+                       return -EFAULT;
+
+               if (chan.channel != 0)
+                       return -EINVAL;
+
+               strcpy(chan.name, "Camera");
+               chan.tuners = 0;
+               chan.flags = 0;
+               chan.type = VIDEO_TYPE_CAMERA;
+               chan.norm = VIDEO_MODE_AUTO;
+
+               if (copy_to_user(arg, &chan, sizeof(chan)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGCHAN successfully called")
+               return 0;
+       }
+
+       case VIDIOCSCHAN: /* set active channel */
+       {
+               struct video_channel chan;
+
+               if (copy_from_user(&chan, arg, sizeof(chan)))
+                       return -EFAULT;
+
+               if (chan.channel != 0)
+                       return -EINVAL;
+
+               DBG(5, "VIDIOCSCHAN successfully called")
+               return 0;
+       }
+
+       case VIDIOCGPICT: /* get image properties of the picture */
+       {
+               if (w9968cf_sensor_get_picture(cam))
+                       return -EIO;
+
+               if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGPICT successfully called")
+               return 0;
+       }
+
+       case VIDIOCSPICT: /* change picture settings */
+       {
+               struct video_picture pict;
+               int err = 0;
+
+               if (copy_from_user(&pict, arg, sizeof(pict)))
+                       return -EFAULT;
+
+               if ( (cam->force_palette || !w9968cf_vpp)
+                    && pict.palette != cam->picture.palette ) {
+                       DBG(4, "Palette %s rejected: only %s is allowed",
+                           symbolic(v4l1_plist, pict.palette),
+                           symbolic(v4l1_plist, cam->picture.palette))
+                       return -EINVAL;
+               }
+
+               if (!w9968cf_valid_palette(pict.palette)) {
+                       DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
+                           symbolic(v4l1_plist, pict.palette))
+                       return -EINVAL;
+               }
+
+               if (!cam->force_palette) {
+                  if (cam->decompression == 0) {
+                     if (w9968cf_need_decompression(pict.palette)) {
+                        DBG(4, "Decompression disabled: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, pict.palette))
+                        return -EINVAL;
+                     }
+                  } else if (cam->decompression == 1) {
+                     if (!w9968cf_need_decompression(pict.palette)) {
+                        DBG(4, "Decompression forced: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, pict.palette))
+                        return -EINVAL;
+                     }
+                  }
+               }
+
+               if (pict.depth != w9968cf_valid_depth(pict.palette)) {
+                       DBG(4, "Requested depth %u bpp is not valid for %s "
+                              "palette: ignored and changed to %u bpp",
+                           pict.depth, symbolic(v4l1_plist, pict.palette),
+                           w9968cf_valid_depth(pict.palette))
+                       pict.depth = w9968cf_valid_depth(pict.palette);
+               }
+
+               if (pict.palette != cam->picture.palette) {
+                       if(*cam->requested_frame
+                          || cam->frame_current->queued) {
+                               err = wait_event_interruptible
+                                     ( cam->wait_queue,
+                                       cam->disconnected ||
+                                       (!*cam->requested_frame &&
+                                        !cam->frame_current->queued) );
+                               if (err)
+                                       return err;
+                               if (cam->disconnected)
+                                       return -ENODEV;
+                       }
+
+                       if (w9968cf_stop_transfer(cam))
+                               goto ioctl_fail;
+
+                       if (w9968cf_set_picture(cam, pict))
+                               goto ioctl_fail;
+
+                       if (w9968cf_start_transfer(cam))
+                               goto ioctl_fail;
+
+               } else if (w9968cf_sensor_update_picture(cam, pict))
+                       return -EIO;
+
+
+               DBG(5, "VIDIOCSPICT successfully called")
+               return 0;
+       }
+
+       case VIDIOCSWIN: /* set capture area */
+       {
+               struct video_window win;
+               int err = 0;
+
+               if (copy_from_user(&win, arg, sizeof(win)))
+                       return -EFAULT;
+
+               DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
+                      "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
+                   win.x, win.y, win.width, win.height)
+
+               if (win.clipcount != 0 || win.flags != 0)
+                       return -EINVAL;
+
+               if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
+                                                     (u16*)&win.height))) {
+                       DBG(4, "Resolution not supported (%ux%u). "
+                              "VIDIOCSWIN failed", win.width, win.height)
+                       return err;
+               }
+
+               if (win.x != cam->window.x ||
+                   win.y != cam->window.y ||
+                   win.width != cam->window.width ||
+                   win.height != cam->window.height) {
+                       if(*cam->requested_frame
+                          || cam->frame_current->queued) {
+                               err = wait_event_interruptible
+                                     ( cam->wait_queue,
+                                       cam->disconnected ||
+                                       (!*cam->requested_frame &&
+                                        !cam->frame_current->queued) );
+                               if (err)
+                                       return err;
+                               if (cam->disconnected)
+                                       return -ENODEV;
+                       }
+
+                       if (w9968cf_stop_transfer(cam))
+                               goto ioctl_fail;
+
+                       /* This _must_ be called before set_window() */
+                       if (w9968cf_set_picture(cam, cam->picture))
+                               goto ioctl_fail;
+
+                       if (w9968cf_set_window(cam, win))
+                               goto ioctl_fail;
+
+                       if (w9968cf_start_transfer(cam))
+                               goto ioctl_fail;
+               }
+
+               DBG(5, "VIDIOCSWIN successfully called. ")
+               return 0;
+       }
+
+       case VIDIOCGWIN: /* get current window properties */
+       {
+               if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGWIN successfully called")
+               return 0;
+       }
+
+       case VIDIOCGMBUF: /* request for memory (mapped) buffer */
+       {
+               struct video_mbuf mbuf;
+               u8 i;
+
+               mbuf.size = cam->nbuffers * cam->frame[0].size;
+               mbuf.frames = cam->nbuffers;
+               for (i = 0; i < cam->nbuffers; i++)
+                       mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
+                                         (unsigned long)cam->frame[0].buffer;
+
+               if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGMBUF successfully called")
+               return 0;
+       }
+
+       case VIDIOCMCAPTURE: /* start the capture to a frame */
+       {
+               struct video_mmap mmap;
+               struct w9968cf_frame_t* fr;
+               int err = 0;
+
+               if (copy_from_user(&mmap, arg, sizeof(mmap)))
+                       return -EFAULT;
+
+               DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
+                   mmap.frame, symbolic(v4l1_plist, mmap.format),
+                   mmap.width, mmap.height)
+
+               if (mmap.frame >= cam->nbuffers) {
+                       DBG(4, "Invalid frame number (%u). "
+                              "VIDIOCMCAPTURE failed", mmap.frame)
+                       return -EINVAL;
+               }
+
+               if (mmap.format!=cam->picture.palette &&
+                   (cam->force_palette || !w9968cf_vpp)) {
+                       DBG(4, "Palette %s rejected: only %s is allowed",
+                           symbolic(v4l1_plist, mmap.format),
+                           symbolic(v4l1_plist, cam->picture.palette))
+                       return -EINVAL;
+               }
+
+               if (!w9968cf_valid_palette(mmap.format)) {
+                       DBG(4, "Palette %s not supported. "
+                              "VIDIOCMCAPTURE failed",
+                           symbolic(v4l1_plist, mmap.format))
+                       return -EINVAL;
+               }
+
+               if (!cam->force_palette) {
+                  if (cam->decompression == 0) {
+                     if (w9968cf_need_decompression(mmap.format)) {
+                        DBG(4, "Decompression disabled: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, mmap.format))
+                        return -EINVAL;
+                     }
+                  } else if (cam->decompression == 1) {
+                     if (!w9968cf_need_decompression(mmap.format)) {
+                        DBG(4, "Decompression forced: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, mmap.format))
+                        return -EINVAL;
+                     }
+                  }
+               }
+
+               if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width,
+                                                     (u16*)&mmap.height))) {
+                       DBG(4, "Resolution not supported (%dx%d). "
+                              "VIDIOCMCAPTURE failed",
+                           mmap.width, mmap.height)
+                       return err;
+               }
+
+               fr = &cam->frame[mmap.frame];
+
+               if (mmap.width  != cam->window.width ||
+                   mmap.height != cam->window.height ||
+                   mmap.format != cam->picture.palette) {
+
+                       struct video_window win;
+                       struct video_picture pict;
+
+                       if(*cam->requested_frame
+                          || cam->frame_current->queued) {
+                               DBG(6, "VIDIOCMCAPTURE. Change settings for "
+                                      "frame #%u: %dx%d, format %s. Wait...",
+                                   mmap.frame, mmap.width, mmap.height,
+                                   symbolic(v4l1_plist, mmap.format))
+                               err = wait_event_interruptible
+                                     ( cam->wait_queue,
+                                       cam->disconnected ||
+                                       (!*cam->requested_frame &&
+                                        !cam->frame_current->queued) );
+                               if (err)
+                                       return err;
+                               if (cam->disconnected)
+                                       return -ENODEV;
+                       }
+
+                       memcpy(&win, &cam->window, sizeof(win));
+                       memcpy(&pict, &cam->picture, sizeof(pict));
+                       win.width = mmap.width;
+                       win.height = mmap.height;
+                       pict.palette = mmap.format;
+
+                       if (w9968cf_stop_transfer(cam))
+                               goto ioctl_fail;
+
+                       /* This before set_window */
+                       if (w9968cf_set_picture(cam, pict))
+                               goto ioctl_fail;
+
+                       if (w9968cf_set_window(cam, win))
+                               goto ioctl_fail;
+
+                       if (w9968cf_start_transfer(cam))
+                               goto ioctl_fail;
+
+               } else  if (fr->queued) {
+
+                       DBG(6, "Wait until frame #%u is free", mmap.frame)
+
+                       err = wait_event_interruptible(cam->wait_queue,
+                                                      cam->disconnected ||
+                                                      (!fr->queued));
+                       if (err)
+                               return err;
+                       if (cam->disconnected)
+                               return -ENODEV;
+               }
+
+               w9968cf_push_frame(cam, mmap.frame);
+               DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
+               return 0;
+       }
+
+       case VIDIOCSYNC: /* wait until the capture of a frame is finished */
+       {
+               unsigned int f_num;
+               struct w9968cf_frame_t* fr;
+               int err = 0;
+
+               if (copy_from_user(&f_num, arg, sizeof(f_num)))
+                       return -EFAULT;
+
+               if (f_num >= cam->nbuffers) {
+                       DBG(4, "Invalid frame number (%u). "
+                              "VIDIOCMCAPTURE failed", f_num)
+                       return -EINVAL;
+               }
+
+               DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
+
+               fr = &cam->frame[f_num];
+
+               switch (fr->status) {
+               case F_UNUSED:
+                       if (!fr->queued) {
+                               DBG(4, "VIDIOSYNC: Frame #%u not requested!",
+                                   f_num)
+                               return -EFAULT;
+                       }
+               case F_ERROR:
+               case F_GRABBING:
+                       err = wait_event_interruptible(cam->wait_queue,
+                                                      (fr->status == F_READY)
+                                                      || cam->disconnected);
+                       if (err)
+                               return err;
+                       if (cam->disconnected)
+                               return -ENODEV;
+                       break;
+               case F_READY:
+                       break;
+               }
+
+               if (w9968cf_vpp)
+                       w9968cf_postprocess_frame(cam, fr);
+
+               fr->status = F_UNUSED;
+
+               DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
+               return 0;
+       }
+
+       case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
+       {
+               struct video_unit unit = {
+                       .video = cam->v4ldev->minor,
+                       .vbi = VIDEO_NO_UNIT,
+                       .radio = VIDEO_NO_UNIT,
+                       .audio = VIDEO_NO_UNIT,
+                       .teletext = VIDEO_NO_UNIT,
+               };
+
+               if (copy_to_user(arg, &unit, sizeof(unit)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGUNIT successfully called")
+               return 0;
+       }
+
+       case VIDIOCKEY:
+               return 0;
+
+       case VIDIOCGFBUF:
+       {
+               if (clear_user(arg, sizeof(struct video_buffer)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGFBUF successfully called")
+               return 0;
+       }
+
+       case VIDIOCGTUNER:
+       {
+               struct video_tuner tuner;
+               if (copy_from_user(&tuner, arg, sizeof(tuner)))
+                       return -EFAULT;
+
+               if (tuner.tuner != 0)
+                       return -EINVAL;
+
+               strcpy(tuner.name, "no_tuner");
+               tuner.rangelow = 0;
+               tuner.rangehigh = 0;
+               tuner.flags = VIDEO_TUNER_NORM;
+               tuner.mode = VIDEO_MODE_AUTO;
+               tuner.signal = 0xffff;
+
+               if (copy_to_user(arg, &tuner, sizeof(tuner)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGTUNER successfully called")
+               return 0;
+       }
+
+       case VIDIOCSTUNER:
+       {
+               struct video_tuner tuner;
+               if (copy_from_user(&tuner, arg, sizeof(tuner)))
+                       return -EFAULT;
+
+               if (tuner.tuner != 0)
+                       return -EINVAL;
+
+               if (tuner.mode != VIDEO_MODE_AUTO)
+                       return -EINVAL;
+
+               DBG(5, "VIDIOCSTUNER successfully called")
+               return 0;
+       }
+
+       case VIDIOCSFBUF:
+       case VIDIOCCAPTURE:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+       case VIDIOCSPLAYMODE:
+       case VIDIOCSWRITEMODE:
+       case VIDIOCGPLAYINFO:
+       case VIDIOCSMICROCODE:
+       case VIDIOCGVBIFMT:
+       case VIDIOCSVBIFMT:
+               DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
+                      "(type 0x%01X, "
+                      "n. 0x%01X, "
+                      "dir. 0x%01X, "
+                      "size 0x%02X)",
+                   V4L1_IOCTL(cmd),
+                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
+
+               return -EINVAL;
+
+       default:
+               DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
+                      "type 0x%01X, "
+                      "n. 0x%01X, "
+                      "dir. 0x%01X, "
+                      "size 0x%02X",
+                   V4L1_IOCTL(cmd),
+                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
+
+               return -ENOIOCTLCMD;
+
+       } /* end of switch */
+
+ioctl_fail:
+       cam->misconfigured = 1;
+       DBG(1, "VIDIOC%s failed because of hardware problems. "
+              "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
+       return -EFAULT;
+}
+
+
+static struct file_operations w9968cf_fops = {
+       .owner =   THIS_MODULE,
+       .open =    w9968cf_open,
+       .release = w9968cf_release,
+       .read =    w9968cf_read,
+       .ioctl =   w9968cf_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .mmap =    w9968cf_mmap,
+       .llseek =  no_llseek,
+};
+
+
+
+/****************************************************************************
+ * USB probe and V4L registration, disconnect and id_table[] definition     *
+ ****************************************************************************/
+
+static int
+w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct w9968cf_device* cam;
+       int err = 0;
+       enum w9968cf_model_id mod_id;
+       struct list_head* ptr;
+       u8 sc = 0; /* number of simultaneous cameras */
+       static unsigned short dev_nr = 0; /* we are handling device number n */
+
+       if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
+           le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
+               mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
+       else if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[1].idVendor &&
+                le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
+               mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
+       else
+               return -ENODEV;
+
+       cam = (struct w9968cf_device*)
+                 kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
+       if (!cam)
+               return -ENOMEM;
+
+       mutex_init(&cam->dev_mutex);
+       mutex_lock(&cam->dev_mutex);
+
+       cam->usbdev = udev;
+       /* NOTE: a local copy is used to avoid possible race conditions */
+       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
+
+       DBG(2, "%s detected", symbolic(camlist, mod_id))
+
+       if (simcams > W9968CF_MAX_DEVICES)
+               simcams = W9968CF_SIMCAMS;
+
+       /* How many cameras are connected ? */
+       mutex_lock(&w9968cf_devlist_mutex);
+       list_for_each(ptr, &w9968cf_dev_list)
+               sc++;
+       mutex_unlock(&w9968cf_devlist_mutex);
+
+       if (sc >= simcams) {
+               DBG(2, "Device rejected: too many connected cameras "
+                      "(max. %u)", simcams)
+               err = -EPERM;
+               goto fail;
+       }
+
+
+       /* Allocate 2 bytes of memory for camera control USB transfers */
+       if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
+               DBG(1,"Couldn't allocate memory for camera control transfers")
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Allocate 8 bytes of memory for USB data transfers to the FSB */
+       if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "Couldn't allocate memory for data "
+                      "transfers to the FSB")
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Register the V4L device */
+       cam->v4ldev = video_device_alloc();
+       if (!cam->v4ldev) {
+               DBG(1, "Could not allocate memory for a V4L structure")
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
+       cam->v4ldev->fops = &w9968cf_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+       cam->v4ldev->dev = &cam->dev;
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L device registration failed")
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(2, "Couldn't find a free /dev/videoX node")
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               goto fail;
+       }
+
+       DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
+
+       /* Set some basic constants */
+       w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
+
+       /* Add a new entry into the list of V4L registered devices */
+       mutex_lock(&w9968cf_devlist_mutex);
+       list_add(&cam->v4llist, &w9968cf_dev_list);
+       mutex_unlock(&w9968cf_devlist_mutex);
+       dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+       w9968cf_turn_on_led(cam);
+
+       w9968cf_i2c_init(cam);
+
+       usb_set_intfdata(intf, cam);
+       mutex_unlock(&cam->dev_mutex);
+       return 0;
+
+fail: /* Free unused memory */
+       kfree(cam->control_buffer);
+       kfree(cam->data_buffer);
+       if (cam->v4ldev)
+               video_device_release(cam->v4ldev);
+       mutex_unlock(&cam->dev_mutex);
+       kfree(cam);
+       return err;
+}
+
+
+static void w9968cf_usb_disconnect(struct usb_interface* intf)
+{
+       struct w9968cf_device* cam =
+          (struct w9968cf_device*)usb_get_intfdata(intf);
+
+       down_write(&w9968cf_disconnect);
+
+       if (cam) {
+               /* Prevent concurrent accesses to data */
+               mutex_lock(&cam->dev_mutex);
+
+               cam->disconnected = 1;
+
+               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
+
+               wake_up_interruptible_all(&cam->open);
+
+               if (cam->users) {
+                       DBG(2, "The device is open (/dev/video%d)! "
+                              "Process name: %s. Deregistration and memory "
+                              "deallocation are deferred on close.",
+                           cam->v4ldev->minor, cam->command)
+                       cam->misconfigured = 1;
+                       w9968cf_stop_transfer(cam);
+                       wake_up_interruptible(&cam->wait_queue);
+               } else
+                       w9968cf_release_resources(cam);
+
+               mutex_unlock(&cam->dev_mutex);
+
+               if (!cam->users)
+                       kfree(cam);
+       }
+
+       up_write(&w9968cf_disconnect);
+}
+
+
+static struct usb_driver w9968cf_usb_driver = {
+       .name =       "w9968cf",
+       .id_table =   winbond_id_table,
+       .probe =      w9968cf_usb_probe,
+       .disconnect = w9968cf_usb_disconnect,
+};
+
+
+
+/****************************************************************************
+ * Module init, exit and intermodule communication                          *
+ ****************************************************************************/
+
+static int __init w9968cf_module_init(void)
+{
+       int err;
+
+       KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
+       KDBG(3, W9968CF_MODULE_AUTHOR)
+
+       if (ovmod_load)
+               request_module("ovcamchip");
+
+       if ((err = usb_register(&w9968cf_usb_driver)))
+               return err;
+
+       return 0;
+}
+
+
+static void __exit w9968cf_module_exit(void)
+{
+       /* w9968cf_usb_disconnect() will be called */
+       usb_deregister(&w9968cf_usb_driver);
+
+       KDBG(2, W9968CF_MODULE_NAME" deregistered")
+}
+
+
+module_init(w9968cf_module_init);
+module_exit(w9968cf_module_exit);
+
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
new file mode 100644 (file)
index 0000000..2836b45
--- /dev/null
@@ -0,0 +1,330 @@
+/***************************************************************************
+ * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
+ *                                                                         *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_H_
+#define _W9968CF_H_
+
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/config.h>
+#include <linux/param.h>
+#include <linux/types.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+
+#include <media/ovcamchip.h>
+
+#include "w9968cf_vpp.h"
+
+
+/****************************************************************************
+ * Default values                                                           *
+ ****************************************************************************/
+
+#define W9968CF_OVMOD_LOAD      1  /* automatic 'ovcamchip' module loading */
+#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
+
+/* Comment/uncomment the following line to enable/disable debugging messages */
+#define W9968CF_DEBUG
+
+/* These have effect only if W9968CF_DEBUG is defined */
+#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
+#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
+
+#define W9968CF_MAX_DEVICES    32
+#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
+
+#define W9968CF_MAX_BUFFERS   32
+#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
+
+/* Maximum data payload sizes in bytes for alternate settings */
+static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
+                                     511, 447, 383, 319, 255, 191, 127,  63};
+#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
+#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
+#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
+#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
+#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
+
+#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
+#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
+
+/* Available video formats */
+struct w9968cf_format {
+       const u16 palette;
+       const u16 depth;
+       const u8 compression;
+};
+
+static const struct w9968cf_format w9968cf_formatlist[] = {
+       { VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
+       { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
+       { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
+       { VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
+       { VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
+       { 0,                      0, 0 }  /* 0 is a terminating entry */
+};
+
+#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
+#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
+#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
+#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
+
+#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
+
+#define W9968CF_MAX_WIDTH      800 /* Has effect if up-scaling is on */
+#define W9968CF_MAX_HEIGHT     600 /* Has effect if up-scaling is on */
+#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
+#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
+
+#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
+#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
+#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
+#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
+#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
+
+#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
+#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
+#define W9968CF_HUE            32768 /* from 0 to 65535 */
+#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
+#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
+#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
+
+#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
+#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
+#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
+#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
+#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
+#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
+
+#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
+#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
+
+
+/****************************************************************************
+ * Globals                                                                  *
+ ****************************************************************************/
+
+#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
+                               "Dual Mode Camera Chip"
+#define W9968CF_MODULE_VERSION  "1:1.33-basic"
+#define W9968CF_MODULE_AUTHOR   "(C) 2002-2004 Luca Risolia"
+#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
+#define W9968CF_MODULE_LICENSE  "GPL"
+
+static const struct usb_device_id winbond_id_table[] = {
+       {
+               /* Creative Labs Video Blaster WebCam Go Plus */
+               USB_DEVICE(0x041e, 0x4003),
+               .driver_info = (unsigned long)"w9968cf",
+       },
+       {
+               /* Generic W996[87]CF JPEG USB Dual Mode Camera */
+               USB_DEVICE(0x1046, 0x9967),
+               .driver_info = (unsigned long)"w9968cf",
+       },
+       { } /* terminating entry */
+};
+
+/* W996[87]CF camera models, internal ids: */
+enum w9968cf_model_id {
+       W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
+       W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
+       W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
+       W9986CF_MOD_AAU = 31,     /* AVerMedia AVerTV USB */
+       W9968CF_MOD_CLVBWG = 34,  /* Creative Labs Video Blaster WebCam Go */
+       W9968CF_MOD_LL = 37,      /* Lebon LDC-035A */
+       W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
+       W9968CF_MOD_OOE = 42,     /* OmniVision OV8610-EDE */
+       W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
+       W9968CF_MOD_PDPII = 46,   /* Pretec Digi Pen-II */
+       W9968CF_MOD_PDP480 = 49,  /* Pretec DigiPen-480 */
+};
+
+enum w9968cf_frame_status {
+       F_READY,            /* finished grabbing & ready to be read/synced */
+       F_GRABBING,         /* in the process of being grabbed into */
+       F_ERROR,            /* something bad happened while processing */
+       F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
+};
+
+struct w9968cf_frame_t {
+       void* buffer;
+       unsigned long size;
+       u32 length;
+       int number;
+       enum w9968cf_frame_status status;
+       struct w9968cf_frame_t* next;
+       u8 queued;
+};
+
+enum w9968cf_vpp_flag {
+       VPP_NONE = 0x00,
+       VPP_UPSCALE = 0x01,
+       VPP_SWAP_YUV_BYTES = 0x02,
+       VPP_DECOMPRESSION = 0x04,
+       VPP_UYVY_TO_RGBX = 0x08,
+};
+
+/* Main device driver structure */
+struct w9968cf_device {
+       struct device dev; /* device structure */
+
+       enum w9968cf_model_id id;   /* private device identifier */
+
+       struct video_device* v4ldev; /* -> V4L structure */
+       struct list_head v4llist;    /* entry of the list of V4L cameras */
+
+       struct usb_device* usbdev;           /* -> main USB structure */
+       struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
+       void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
+       u16* control_buffer;                 /* -> buffer for control req.*/
+       u16* data_buffer;                    /* -> data to send to the FSB */
+
+       struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
+       struct w9968cf_frame_t frame_tmp; /* temporary frame */
+       struct w9968cf_frame_t frame_vpp; /* helper frame.*/
+       struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
+       struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
+
+       u8 max_buffers,   /* number of requested buffers */
+          force_palette, /* yes=1/no=0 */
+          force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
+          double_buffer, /* hardware double buffering yes=1/no=0 */
+          clamping,      /* video data clamping yes=1/no=0 */
+          filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
+          capture,       /* 0=disabled, 1=enabled */
+          largeview,     /* 0=disabled, 1=enabled */
+          decompression, /* 0=disabled, 1=forced, 2=allowed */
+          upscaling;     /* software image scaling, 0=enabled, 1=disabled */
+
+       struct video_picture picture; /* current picture settings */
+       struct video_window window;   /* current window settings */
+
+       u16 hw_depth,    /* depth (used by the chip) */
+           hw_palette,  /* palette (used by the chip) */
+           hw_width,    /* width (used by the chip) */
+           hw_height,   /* height (used by the chip) */
+           hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
+           vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
+           start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
+           start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
+
+       enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
+
+       u8 nbuffers,      /* number of allocated frame buffers */
+          altsetting,    /* camera alternate setting */
+          disconnected,  /* flag: yes=1, no=0 */
+          misconfigured, /* flag: yes=1, no=0 */
+          users,         /* flag: number of users holding the device */
+          streaming;     /* flag: yes=1, no=0 */
+
+       u8 sensor_initialized; /* flag: yes=1, no=0 */
+
+       /* Determined by the image sensor type: */
+       int sensor,       /* type of image sensor chip (CC_*) */
+           monochrome;   /* image sensor is (probably) monochrome */
+       u16 maxwidth,     /* maximum width supported by the image sensor */
+           maxheight,    /* maximum height supported by the image sensor */
+           minwidth,     /* minimum width supported by the image sensor */
+           minheight;    /* minimum height supported by the image sensor */
+       u8  auto_brt,     /* auto brightness enabled flag */
+           auto_exp,     /* auto exposure enabled flag */
+           backlight,    /* backlight exposure algorithm flag */
+           mirror,       /* image is reversed horizontally */
+           lightfreq,    /* power (lighting) frequency */
+           bandfilt;     /* banding filter enabled flag */
+       s8  clockdiv;     /* clock divisor */
+
+       /* I2C interface to kernel */
+       struct i2c_adapter i2c_adapter;
+       struct i2c_client* sensor_client;
+
+       /* Locks */
+       struct mutex dev_mutex,    /* for probe, disconnect,open and close */
+                        fileop_mutex; /* for read and ioctl */
+       spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
+                  flist_lock; /* for requested frame list accesses */
+       wait_queue_head_t open, wait_queue;
+
+       char command[16]; /* name of the program holding the device */
+};
+
+
+/****************************************************************************
+ * Macros for debugging                                                     *
+ ****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef W9968CF_DEBUG
+/* For device specific debugging messages */
+#      define DBG(level, fmt, args...)                                       \
+{                                                                             \
+       if ( ((specific_debug) && (debug == (level))) ||                      \
+            ((!specific_debug) && (debug >= (level))) ) {                    \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->dev, fmt "\n", ## args);                \
+               else if ((level) == 2 || (level) == 3)                        \
+                       dev_info(&cam->dev, fmt "\n", ## args);               \
+               else if ((level) == 4)                                        \
+                       dev_warn(&cam->dev, fmt "\n", ## args);               \
+               else if ((level) >= 5)                                        \
+                       dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+}
+/* For generic kernel (not device specific) messages */
+#      define KDBG(level, fmt, args...)                                      \
+{                                                                             \
+       if ( ((specific_debug) && (debug == (level))) ||                      \
+            ((!specific_debug) && (debug >= (level))) ) {                    \
+               if ((level) >= 1 && (level) <= 4)                             \
+                       pr_info("w9968cf: " fmt "\n", ## args);               \
+               else if ((level) >= 5)                                        \
+                       pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__,  \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+}
+#else
+       /* Not debugging: nothing */
+#      define DBG(level, fmt, args...) do {;} while(0);
+#      define KDBG(level, fmt, args...) do {;} while(0);
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
+
+#endif /* _W9968CF_H_ */
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h
new file mode 100644 (file)
index 0000000..59decbf
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Video decoder for the W996[87]CF driver for Linux.                      *
+ *                                                                         *
+ * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_DECODER_H_
+#define _W9968CF_DECODER_H_
+
+/* Comment/uncomment this for high/low quality of compressed video */
+#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
+
+#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
+static const unsigned char Y_QUANTABLE[64] = {
+       16,  11,  10,  16,  24,  40,  51,  61,
+       12,  12,  14,  19,  26,  58,  60,  55,
+       14,  13,  16,  24,  40,  57,  69,  56,
+       14,  17,  22,  29,  51,  87,  80,  62,
+       18,  22,  37,  56,  68, 109, 103,  77,
+       24,  35,  55,  64,  81, 104, 113,  92,
+       49,  64,  78,  87, 103, 121, 120, 101,
+       72,  92,  95,  98, 112, 100, 103,  99
+};
+
+static const unsigned char UV_QUANTABLE[64] = {
+       17,  18,  24,  47,  99,  99,  99,  99,
+       18,  21,  26,  66,  99,  99,  99,  99,
+       24,  26,  56,  99,  99,  99,  99,  99,
+       47,  66,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99
+};
+#else
+static const unsigned char Y_QUANTABLE[64] = {
+        8,   5,   5,   8,  12,  20,  25,  30,
+        6,   6,   7,   9,  13,  29,  30,  27,
+        7,   6,   8,  12,  20,  28,  34,  28,
+        7,   8,  11,  14,  25,  43,  40,  31,
+        9,  11,  18,  28,  34,  54,  51,  38,
+       12,  17,  27,  32,  40,  52,  56,  46,
+       24,  32,  39,  43,  51,  60,  60,  50,
+       36,  46,  47,  49,  56,  50,  51,  49
+};
+
+static const unsigned char UV_QUANTABLE[64] = {
+        8,   9,  12,  23,  49,  49,  49,  49,
+        9,  10,  13,  33,  49,  49,  49,  49,
+       12,  13,  28,  49,  49,  49,  49,  49,
+       23,  33,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49
+};
+#endif
+
+#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
+#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
+#define W9968CF_DEC_ERR_NO_SOI          -3
+#define W9968CF_DEC_ERR_NO_SOF0         -4
+#define W9968CF_DEC_ERR_NO_SOS          -5
+#define W9968CF_DEC_ERR_NO_EOI          -6
+
+extern void w9968cf_init_decoder(void);
+extern int w9968cf_check_headers(const unsigned char* Pin,
+                                const unsigned long BUF_SIZE);
+extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE,
+                         const unsigned W, const unsigned H, char* Pout);
+
+#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h
new file mode 100644 (file)
index 0000000..88c9b6c
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Interface for video post-processing functions for the W996[87]CF driver *
+ * for Linux.                                                              *
+ *                                                                         *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_VPP_H_
+#define _W9968CF_VPP_H_
+
+#include <linux/module.h>
+#include <asm/types.h>
+
+struct w9968cf_vpp_t {
+       struct module* owner;
+       int (*check_headers)(const unsigned char*, const unsigned long);
+       int (*decode)(const char*, const unsigned long, const unsigned,
+                     const unsigned, char*);
+       void (*swap_yuvbytes)(void*, unsigned long);
+       void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
+       void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
+
+       u8 busy; /* read-only flag: module is/is not in use */
+};
+
+#endif /* _W9968CF_VPP_H_ */
index 8cb64f8a8a9182b8e5f9a146c8d4f3fba8d9381d..d81a88bbe43d02a8aac3f61a575facb07153615a 100644 (file)
@@ -79,21 +79,26 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
                          void *arg)
 {
        struct wm8775_state *state = i2c_get_clientdata(client);
-       struct v4l2_audio *input = arg;
+       struct v4l2_routing *route = arg;
        struct v4l2_control *ctrl = arg;
 
        switch (cmd) {
-       case VIDIOC_S_AUDIO:
+       case VIDIOC_INT_G_AUDIO_ROUTING:
+               route->input = state->input;
+               route->output = 0;
+               break;
+
+       case VIDIOC_INT_S_AUDIO_ROUTING:
                /* There are 4 inputs and one output. Zero or more inputs
                   are multiplexed together to the output. Hence there are
                   16 combinations.
                   If only one input is active (the normal case) then the
                   input values 1, 2, 4 or 8 should be used. */
-               if (input->index > 15) {
-                       v4l_err(client, "Invalid input %d.\n", input->index);
+               if (route->input > 15) {
+                       v4l_err(client, "Invalid input %d.\n", route->input);
                        return -EINVAL;
                }
-               state->input = input->index;
+               state->input = route->input;
                if (state->muted)
                        break;
                wm8775_write(client, R21, 0x0c0);
@@ -102,11 +107,6 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
                wm8775_write(client, R21, 0x100 + state->input);
                break;
 
-       case VIDIOC_G_AUDIO:
-               memset(input, 0, sizeof(*input));
-               input->index = state->input;
-               break;
-
        case VIDIOC_G_CTRL:
                if (ctrl->id != V4L2_CID_AUDIO_MUTE)
                        return -EINVAL;
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
new file mode 100644 (file)
index 0000000..d749199
--- /dev/null
@@ -0,0 +1,3 @@
+zc0301-objs     := zc0301_core.o zc0301_pas202bcb.o
+
+obj-$(CONFIG_USB_ZC0301)        += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
new file mode 100644 (file)
index 0000000..b9c93b8
--- /dev/null
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ZC0301_H_
+#define _ZC0301_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include "zc0301_sensor.h"
+
+/*****************************************************************************/
+
+#define ZC0301_DEBUG
+#define ZC0301_DEBUG_LEVEL         2
+#define ZC0301_MAX_DEVICES         64
+#define ZC0301_FORCE_MUNMAP        0
+#define ZC0301_MAX_FRAMES          32
+#define ZC0301_COMPRESSION_QUALITY 0
+#define ZC0301_URBS                2
+#define ZC0301_ISO_PACKETS         7
+#define ZC0301_ALTERNATE_SETTING   7
+#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
+#define ZC0301_CTRL_TIMEOUT        100
+#define ZC0301_FRAME_TIMEOUT       2
+
+/*****************************************************************************/
+
+ZC0301_ID_TABLE
+ZC0301_SENSOR_TABLE
+
+enum zc0301_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct zc0301_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum zc0301_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum zc0301_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum zc0301_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum zc0301_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+struct zc0301_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DECLARE_RWSEM(zc0301_disconnect);
+
+struct zc0301_device {
+       struct video_device* v4ldev;
+
+       struct zc0301_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[ZC0301_URBS];
+       void* transfer_buffer[ZC0301_URBS];
+       u8* control_buffer;
+
+       struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum zc0301_io_method io;
+       enum zc0301_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct zc0301_module_param module_param;
+
+       enum zc0301_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
+{
+       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
+}
+
+void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ZC0301_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("zc0301: " fmt "\n", ## args);                \
+               else if ((level) == 3)                                        \
+                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+        __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ZC0301_H_ */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
new file mode 100644 (file)
index 0000000..0fad397
--- /dev/null
@@ -0,0 +1,2055 @@
+/***************************************************************************
+ * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Informations about the chip internals needed to enable the I2C protocol *
+ * have been taken from the documentation of the ZC030x Video4Linux1       *
+ * driver written by Andrew Birkett <andy@nobugs.org>                      *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "zc0301.h"
+
+/*****************************************************************************/
+
+#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
+                             "Image Processor and Control Chip"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ZC0301_MODULE_LICENSE "GPL"
+#define ZC0301_MODULE_VERSION "1:1.03"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, zc0301_id_table);
+
+MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
+MODULE_VERSION(ZC0301_MODULE_VERSION);
+MODULE_LICENSE(ZC0301_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                "\n -1 = use next available (default)"
+                "\n  n = use minor number n (integer >= 0)"
+                "\nYou can specify up to "
+                __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
+                "\nFor example:"
+                "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                "\nthe second registered camera and use auto for the first"
+                "\none and for every other camera."
+                "\n");
+
+static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                              ZC0301_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                "\n<0|1[,...]> Force the application to unmap previously"
+                "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                "\nthis feature. This parameter is specific for each"
+                "\ndetected camera."
+                "\n 0 = do not force memory unmapping"
+                "\n 1 = force memory unmapping (save memory)"
+                "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                "\n");
+
+static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                                      ZC0301_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                "\n<n[,...]> Timeout for a video frame in seconds."
+                "\nThis parameter is specific for each detected camera."
+                "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
+                "\n");
+
+#ifdef ZC0301_DEBUG
+static unsigned short debug = ZC0301_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                "\n<n> Debugging information level, from 0 to 3:"
+                "\n0 = none (use carefully)"
+                "\n1 = critical errors"
+                "\n2 = significant informations"
+                "\n3 = more verbose messages"
+                "\nLevel 3 is useful for testing only, when only "
+                "one device is used."
+                "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
+                "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+zc0301_request_buffers(struct zc0301_device* cam, u32 count,
+                      enum zc0301_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > ZC0301_MAX_FRAMES)
+               count = ZC0301_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void zc0301_release_buffers(struct zc0301_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void zc0301_empty_framequeues(struct zc0301_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void zc0301_requeue_outqueue(struct zc0301_device* cam)
+{
+       struct zc0301_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void zc0301_queue_unusedframes(struct zc0301_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       int res;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
+                             value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (index 0x%04X, "
+                      "value 0x%02X, error %d)",index, value, res);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int zc0301_read_reg(struct zc0301_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
+                             0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%04X, error %d)",
+                   index, res);
+
+       PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
+{
+       int err = 0, res, r0, r1;
+
+       err += zc0301_write_reg(cam, 0x0092, address);
+       err += zc0301_write_reg(cam, 0x0090, 0x02);
+
+       msleep(1);
+
+       res = zc0301_read_reg(cam, 0x0091);
+       if (res < 0)
+               err += res;
+       r0 = zc0301_read_reg(cam, 0x0095);
+       if (r0 < 0)
+               err += r0;
+       r1 = zc0301_read_reg(cam, 0x0096);
+       if (r1 < 0)
+               err += r1;
+
+       res = (length <= 1) ? r0 : r0 | (r1 << 8);
+
+       if (err)
+               DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
+                   address, res);
+
+
+       PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
+
+       return err ? -1 : res;
+}
+
+
+int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
+{
+       int err = 0, res;
+
+       err += zc0301_write_reg(cam, 0x0092, address);
+       err += zc0301_write_reg(cam, 0x0093, value & 0xff);
+       err += zc0301_write_reg(cam, 0x0094, value >> 8);
+       err += zc0301_write_reg(cam, 0x0090, 0x01);
+
+       msleep(1);
+
+       res = zc0301_read_reg(cam, 0x0091);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
+                   address, value);
+
+       PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
+
+       return err ? -1 : 0;
+}
+
+/*****************************************************************************/
+
+static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct zc0301_device* cam = urb->context;
+       struct zc0301_frame_t** f;
+       size_t imagesize;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int len, status;
+               void *pos;
+               u16* soi;
+               u8 sof;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               sof = (*(soi = pos) == 0xd8ff);
+
+               PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
+
+               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+                       if (sof) {
+                               (*f)->state = F_GRABBING;
+                               (*f)->buf.bytesused = 0;
+                               do_gettimeofday(&(*f)->buf.timestamp);
+                               DBG(3, "SOF detected: new video frame");
+                       }
+
+               if ((*f)->state == F_GRABBING) {
+                       if (sof && (*f)->buf.bytesused)
+                                       goto end_of_frame;
+
+                       if ((*f)->buf.bytesused + len > imagesize) {
+                               DBG(3, "Video frame size exceeded");
+                               (*f)->state = F_ERROR;
+                               continue;
+                       }
+
+                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
+                       (*f)->buf.bytesused += len;
+
+                       if ((*f)->buf.bytesused == imagesize) {
+                               u32 b;
+end_of_frame:
+                               b = (*f)->buf.bytesused;
+                               (*f)->state = F_DONE;
+                               (*f)->buf.sequence= ++cam->frame_count;
+                               spin_lock(&cam->queue_lock);
+                               list_move_tail(&(*f)->frame, &cam->outqueue);
+                               if (!list_empty(&cam->inqueue))
+                                       (*f) = list_entry(cam->inqueue.next,
+                                                      struct zc0301_frame_t,
+                                                         frame);
+                               else
+                                       (*f) = NULL;
+                               spin_unlock(&cam->queue_lock);
+                               DBG(3, "Video frame captured: : %lu bytes",
+                                      (unsigned long)(b));
+
+                               if (!(*f))
+                                       goto resubmit_urb;
+
+                               if (sof)
+                                       goto start_of_frame;
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int zc0301_start_transfer(struct zc0301_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
+                                              512, 768, 1023};
+       const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = ZC0301_ISO_PACKETS;
+               urb->complete = zc0301_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < ZC0301_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int zc0301_stop_transfer(struct zc0301_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = ZC0301_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int zc0301_stream_interrupt(struct zc0301_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    ZC0301_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. To "
+                      "use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_set_compression(struct zc0301_device* cam,
+                      struct v4l2_jpegcompression* compression)
+{
+       int r, err = 0;
+
+       if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
+               err += r;
+       err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
+
+       return err ? -EIO : 0;
+}
+
+
+static int zc0301_init(struct zc0301_device* cam)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+               cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       if ((err = zc0301_set_compression(cam, &cam->compression))) {
+               DBG(3, "set_compression() failed");
+               return err;
+       }
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void zc0301_release_resources(struct zc0301_device* cam)
+{
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int zc0301_open(struct inode* inode, struct file* filp)
+{
+       struct zc0301_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&zc0301_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&zc0301_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&zc0301_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&zc0301_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = zc0301_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = zc0301_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       zc0301_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&zc0301_disconnect);
+       return err;
+}
+
+
+static int zc0301_release(struct inode* inode, struct file* filp)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       zc0301_stop_transfer(cam);
+
+       zc0301_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               zc0301_release_resources(cam);
+               usb_put_dev(cam->usbdev);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose the read "
+                      "method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       zc0301_empty_framequeues(cam);
+               zc0301_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       zc0301_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err ? err : count;
+}
+
+
+static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               zc0301_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void zc0301_vm_open(struct vm_area_struct* vma)
+{
+       struct zc0301_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void zc0301_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct zc0301_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct zc0301_vm_ops = {
+       .open = zc0301_vm_open,
+       .close = zc0301_vm_close,
+};
+
+
+static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &zc0301_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       zc0301_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "zc0301",
+               .version = ZC0301_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       const enum zc0301_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (!s->set_crop) {
+               memcpy(rect, &(s->_rect), sizeof(*rect));
+               if (copy_to_user(arg, &crop, sizeof(crop)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       rect->left &= ~7L;
+       rect->top &= ~7L;
+       if (rect->width < 8)
+               rect->width = 8;
+       if (rect->height < 8)
+               rect->height = 8;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+       rect->width &= ~7L;
+       rect->height &= ~7L;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               zc0301_release_buffers(cam);
+
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width;
+       s->pix_format.height = rect->height;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               zc0301_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               zc0301_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "JPEG");
+               fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = 0;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
+                       void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       const enum zc0301_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       if (!s->set_crop) {
+               pix->width = rect.width;
+               pix->height = rect.height;
+       } else {
+               rect.width = pix->width;
+               rect.height = pix->height;
+       }
+
+       if (rect.width < 8)
+               rect.width = 8;
+       if (rect.height < 8)
+               rect.height = 8;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+       rect.width &= ~7L;
+       rect.height &= ~7L;
+
+       pix->width = rect.width;
+       pix->height = rect.height;
+       pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv;
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = 0;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               zc0301_release_buffers(cam);
+
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               zc0301_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               zc0301_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum zc0301_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       err += zc0301_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. "
+                              "Previous buffers are still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       zc0301_empty_framequeues(cam);
+
+       zc0301_release_buffers(cam);
+       if (rb.count)
+               rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               zc0301_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
+                   void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct zc0301_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       zc0301_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
+               sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
+                            unsigned int cmd, void __user * arg)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return zc0301_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return zc0301_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return zc0301_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return zc0301_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return zc0301_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return zc0301_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return zc0301_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return zc0301_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return zc0301_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return zc0301_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return zc0301_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return zc0301_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return zc0301_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return zc0301_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return zc0301_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return zc0301_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return zc0301_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return zc0301_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return zc0301_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return zc0301_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return zc0301_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return zc0301_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int zc0301_ioctl(struct inode* inode, struct file* filp,
+                       unsigned int cmd, unsigned long arg)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "zc0301", cmd);
+
+       err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+
+static struct file_operations zc0301_fops = {
+       .owner =   THIS_MODULE,
+       .open =    zc0301_open,
+       .release = zc0301_release,
+       .ioctl =   zc0301_ioctl,
+       .read =    zc0301_read,
+       .poll =    zc0301_poll,
+       .mmap =    zc0301_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+static int
+zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct zc0301_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0;
+
+       if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       DBG(2, "ZC0301 Image Processor and Control Chip detected "
+              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+       for  (i = 0; zc0301_sensor_table[i]; i++) {
+               err = zc0301_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err)
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+       else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (zc0301_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &zc0301_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void zc0301_usb_disconnect(struct usb_interface* intf)
+{
+       struct zc0301_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&zc0301_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               zc0301_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               zc0301_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&zc0301_disconnect);
+}
+
+
+static struct usb_driver zc0301_usb_driver = {
+       .name =       "zc0301",
+       .id_table =   zc0301_id_table,
+       .probe =      zc0301_usb_probe,
+       .disconnect = zc0301_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init zc0301_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
+       KDBG(3, ZC0301_MODULE_AUTHOR);
+
+       if ((err = usb_register(&zc0301_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit zc0301_module_exit(void)
+{
+       usb_deregister(&zc0301_usb_driver);
+}
+
+
+module_init(zc0301_module_init);
+module_exit(zc0301_module_exit);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
new file mode 100644 (file)
index 0000000..eaadf02
--- /dev/null
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
+ * Processor and Control Chip                                              *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+/*
+   NOTE: Sensor controls are disabled for now, becouse changing them while
+        streaming sometimes results in out-of-sync video frames. We'll use
+        the default initialization, until we know how to stop and start video
+        in the chip. However, the image quality still looks good under various
+        light conditions.
+*/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct zc0301_device* cam)
+{
+       int err = 0;
+
+       err += zc0301_write_reg(cam, 0x0002, 0x00);
+       err += zc0301_write_reg(cam, 0x0003, 0x02);
+       err += zc0301_write_reg(cam, 0x0004, 0x80);
+       err += zc0301_write_reg(cam, 0x0005, 0x01);
+       err += zc0301_write_reg(cam, 0x0006, 0xE0);
+       err += zc0301_write_reg(cam, 0x0098, 0x00);
+       err += zc0301_write_reg(cam, 0x009A, 0x03);
+       err += zc0301_write_reg(cam, 0x011A, 0x00);
+       err += zc0301_write_reg(cam, 0x011C, 0x03);
+       err += zc0301_write_reg(cam, 0x009B, 0x01);
+       err += zc0301_write_reg(cam, 0x009C, 0xE6);
+       err += zc0301_write_reg(cam, 0x009D, 0x02);
+       err += zc0301_write_reg(cam, 0x009E, 0x86);
+
+       err += zc0301_i2c_write(cam, 0x02, 0x02);
+       err += zc0301_i2c_write(cam, 0x0A, 0x01);
+       err += zc0301_i2c_write(cam, 0x0B, 0x01);
+       err += zc0301_i2c_write(cam, 0x0D, 0x00);
+       err += zc0301_i2c_write(cam, 0x12, 0x05);
+       err += zc0301_i2c_write(cam, 0x13, 0x63);
+       err += zc0301_i2c_write(cam, 0x15, 0x70);
+
+       err += zc0301_write_reg(cam, 0x0101, 0xB7);
+       err += zc0301_write_reg(cam, 0x0100, 0x0D);
+       err += zc0301_write_reg(cam, 0x0189, 0x06);
+       err += zc0301_write_reg(cam, 0x01AD, 0x00);
+       err += zc0301_write_reg(cam, 0x01C5, 0x03);
+       err += zc0301_write_reg(cam, 0x01CB, 0x13);
+       err += zc0301_write_reg(cam, 0x0250, 0x08);
+       err += zc0301_write_reg(cam, 0x0301, 0x08);
+       err += zc0301_write_reg(cam, 0x018D, 0x70);
+       err += zc0301_write_reg(cam, 0x0008, 0x03);
+       err += zc0301_write_reg(cam, 0x01C6, 0x04);
+       err += zc0301_write_reg(cam, 0x01CB, 0x07);
+       err += zc0301_write_reg(cam, 0x0120, 0x11);
+       err += zc0301_write_reg(cam, 0x0121, 0x37);
+       err += zc0301_write_reg(cam, 0x0122, 0x58);
+       err += zc0301_write_reg(cam, 0x0123, 0x79);
+       err += zc0301_write_reg(cam, 0x0124, 0x91);
+       err += zc0301_write_reg(cam, 0x0125, 0xA6);
+       err += zc0301_write_reg(cam, 0x0126, 0xB8);
+       err += zc0301_write_reg(cam, 0x0127, 0xC7);
+       err += zc0301_write_reg(cam, 0x0128, 0xD3);
+       err += zc0301_write_reg(cam, 0x0129, 0xDE);
+       err += zc0301_write_reg(cam, 0x012A, 0xE6);
+       err += zc0301_write_reg(cam, 0x012B, 0xED);
+       err += zc0301_write_reg(cam, 0x012C, 0xF3);
+       err += zc0301_write_reg(cam, 0x012D, 0xF8);
+       err += zc0301_write_reg(cam, 0x012E, 0xFB);
+       err += zc0301_write_reg(cam, 0x012F, 0xFF);
+       err += zc0301_write_reg(cam, 0x0130, 0x26);
+       err += zc0301_write_reg(cam, 0x0131, 0x23);
+       err += zc0301_write_reg(cam, 0x0132, 0x20);
+       err += zc0301_write_reg(cam, 0x0133, 0x1C);
+       err += zc0301_write_reg(cam, 0x0134, 0x16);
+       err += zc0301_write_reg(cam, 0x0135, 0x13);
+       err += zc0301_write_reg(cam, 0x0136, 0x10);
+       err += zc0301_write_reg(cam, 0x0137, 0x0D);
+       err += zc0301_write_reg(cam, 0x0138, 0x0B);
+       err += zc0301_write_reg(cam, 0x0139, 0x09);
+       err += zc0301_write_reg(cam, 0x013A, 0x07);
+       err += zc0301_write_reg(cam, 0x013B, 0x06);
+       err += zc0301_write_reg(cam, 0x013C, 0x05);
+       err += zc0301_write_reg(cam, 0x013D, 0x04);
+       err += zc0301_write_reg(cam, 0x013E, 0x03);
+       err += zc0301_write_reg(cam, 0x013F, 0x02);
+       err += zc0301_write_reg(cam, 0x010A, 0x4C);
+       err += zc0301_write_reg(cam, 0x010B, 0xF5);
+       err += zc0301_write_reg(cam, 0x010C, 0xFF);
+       err += zc0301_write_reg(cam, 0x010D, 0xF9);
+       err += zc0301_write_reg(cam, 0x010E, 0x51);
+       err += zc0301_write_reg(cam, 0x010F, 0xF5);
+       err += zc0301_write_reg(cam, 0x0110, 0xFB);
+       err += zc0301_write_reg(cam, 0x0111, 0xED);
+       err += zc0301_write_reg(cam, 0x0112, 0x5F);
+       err += zc0301_write_reg(cam, 0x0180, 0x00);
+       err += zc0301_write_reg(cam, 0x0019, 0x00);
+       err += zc0301_write_reg(cam, 0x0087, 0x20);
+       err += zc0301_write_reg(cam, 0x0088, 0x21);
+
+       err += zc0301_i2c_write(cam, 0x20, 0x02);
+       err += zc0301_i2c_write(cam, 0x21, 0x1B);
+       err += zc0301_i2c_write(cam, 0x03, 0x44);
+       err += zc0301_i2c_write(cam, 0x0E, 0x01);
+       err += zc0301_i2c_write(cam, 0x0F, 0x00);
+
+       err += zc0301_write_reg(cam, 0x01A9, 0x14);
+       err += zc0301_write_reg(cam, 0x01AA, 0x24);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0191, 0x02);
+       err += zc0301_write_reg(cam, 0x0192, 0x1B);
+       err += zc0301_write_reg(cam, 0x0195, 0x00);
+       err += zc0301_write_reg(cam, 0x0196, 0x00);
+       err += zc0301_write_reg(cam, 0x0197, 0x4D);
+       err += zc0301_write_reg(cam, 0x018C, 0x10);
+       err += zc0301_write_reg(cam, 0x018F, 0x20);
+       err += zc0301_write_reg(cam, 0x001D, 0x44);
+       err += zc0301_write_reg(cam, 0x001E, 0x6F);
+       err += zc0301_write_reg(cam, 0x001F, 0xAD);
+       err += zc0301_write_reg(cam, 0x0020, 0xEB);
+       err += zc0301_write_reg(cam, 0x0087, 0x0F);
+       err += zc0301_write_reg(cam, 0x0088, 0x0E);
+       err += zc0301_write_reg(cam, 0x0180, 0x40);
+       err += zc0301_write_reg(cam, 0x0192, 0x1B);
+       err += zc0301_write_reg(cam, 0x0191, 0x02);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0116, 0x1D);
+       err += zc0301_write_reg(cam, 0x0117, 0x40);
+       err += zc0301_write_reg(cam, 0x0118, 0x99);
+       err += zc0301_write_reg(cam, 0x0180, 0x42);
+       err += zc0301_write_reg(cam, 0x0116, 0x1D);
+       err += zc0301_write_reg(cam, 0x0117, 0x40);
+       err += zc0301_write_reg(cam, 0x0118, 0x99);
+       err += zc0301_write_reg(cam, 0x0007, 0x00);
+
+       err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+       msleep(100);
+
+       return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct zc0301_device* cam,
+                             struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = zc0301_i2c_read(cam, 0x04, 1),
+                           r2 = zc0301_i2c_read(cam, 0x05, 1);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case ZC0301_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
+                       return -EIO;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas202bcb_set_ctrl(struct zc0301_device* cam,
+                             const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += zc0301_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += zc0301_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += zc0301_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case ZC0301_V4L2_CID_GREEN_BALANCE:
+               err += zc0301_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+               err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static struct zc0301_sensor pas202bcb = {
+       .name = "PAS202BCB",
+       .init = &pas202bcb_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+       },
+       .get_ctrl = &pas202bcb_get_ctrl,
+       .set_ctrl = &pas202bcb_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_JPEG,
+               .priv = 8,
+       },
+};
+
+
+int zc0301_probe_pas202bcb(struct zc0301_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       err += zc0301_write_reg(cam, 0x0000, 0x01);
+       err += zc0301_write_reg(cam, 0x0010, 0x0e);
+       err += zc0301_write_reg(cam, 0x0001, 0x01);
+       err += zc0301_write_reg(cam, 0x0012, 0x03);
+       err += zc0301_write_reg(cam, 0x0012, 0x01);
+       err += zc0301_write_reg(cam, 0x008d, 0x08);
+
+       msleep(10);
+
+       r0 = zc0301_i2c_read(cam, 0x00, 1);
+       r1 = zc0301_i2c_read(cam, 0x01, 1);
+
+       if (r0 < 0 || r1 < 0 || err)
+               return -EIO;
+
+       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x017)
+               return -ENODEV;
+
+       zc0301_attach_sensor(cam, &pas202bcb);
+
+       return 0;
+}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
new file mode 100644 (file)
index 0000000..1f95c28
--- /dev/null
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * API for image sensors connected to the ZC030! Image Processor and       *
+ * Control Chip                                                            *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ZC0301_SENSOR_H_
+#define _ZC0301_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct zc0301_device;
+struct zc0301_sensor;
+
+/*****************************************************************************/
+
+extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+
+#define ZC0301_SENSOR_TABLE                                                   \
+/* Weak detections must go at the end of the list */                          \
+static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
+       &zc0301_probe_pas202bcb,                                              \
+       NULL,                                                                 \
+};
+
+extern struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
+
+extern void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
+
+#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = (intclass)
+
+#define ZC0301_ID_TABLE                                                       \
+static const struct usb_device_id zc0301_id_table[] =  {                      \
+       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
+       { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+       { }                                                                   \
+};
+
+/*****************************************************************************/
+
+extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
+extern int zc0301_read_reg(struct zc0301_device*, u16 index);
+extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
+extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
+
+/*****************************************************************************/
+
+#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+
+struct zc0301_sensor {
+       char name[32];
+
+       struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
+       struct v4l2_cropcap cropcap;
+       struct v4l2_pix_format pix_format;
+
+       int (*init)(struct zc0301_device*);
+       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct zc0301_device*,
+                       const struct v4l2_control* ctrl);
+       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
+
+       /* Private */
+       struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+#endif /* _ZC0301_SENSOR_H_ */
index ad04a129499d59f887e2e33084cf70612b8759ae..0166f555a5ca1b37c5399d85b95137dd0c1705ed 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * zoran - Iomega Buz driver
  *
  * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
index b22dbb6d18f6407a276d27ec0cb0a987b7a5f8c1..0a85c9e7fb4824803abdf0801268bfbb9ac695bd 100644 (file)
@@ -4,7 +4,7 @@
  * Media Labs LML33/LML33R10.
  *
  * This part handles card-specific data and detection
- * 
+ *
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  *
  * Currently maintained by:
index e5b6acd3eedc248c85709f3c8beba953db87847b..ad997c30bee540bc43e50b1ab90b6de88d3d69a2 100644 (file)
@@ -4,7 +4,7 @@
  * Media Labs LML33/LML33R10.
  *
  * This part handles card-specific data and detection
- * 
+ *
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  *
  * Currently maintained by:
index 4e15afdec4c9d4b60eb8ddc5616899dab2554a91..c690b2ee880a4fe8f44f6496177d345703962329 100644 (file)
@@ -4,7 +4,7 @@
  * Media Labs LML33/LML33R10.
  *
  * This part handles device access (PCI/I2C/codec/...)
- * 
+ *
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  *
  * Currently maintained by:
@@ -492,7 +492,7 @@ zr36057_set_vfe (struct zoran              *zr,
        /* (Ronald) don't write this if overlay_mask = NULL */
        if (zr->overlay_mask) {
                /* Write overlay clipping mask data, but don't enable overlay clipping */
-               /* RJ: since this makes only sense on the screen, we use 
+               /* RJ: since this makes only sense on the screen, we use
                 * zr->overlay_settings.width instead of video_width */
 
                mask_line_size = (BUZ_MAX_WIDTH + 31) / 32;
@@ -819,12 +819,12 @@ zr36057_set_jpg (struct zoran          *zr,
        if (zr->card.vfe_pol.hsync_pol)
                btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
        else
-               btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);           
+               btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR);
        reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) |
              (tvn->Wt << ZR36057_HSP_LineTot);
        btwrite(reg, ZR36057_HSP);
        reg = ((zr->jpg_settings.img_x +
-               tvn->HStart + 4) << ZR36057_FHAP_NAX) |
+               tvn->HStart + 4) << ZR36057_FHAP_NAX) |
              (zr->jpg_settings.img_width << ZR36057_FHAP_PAX);
        btwrite(reg, ZR36057_FHAP);
 
@@ -1272,15 +1272,15 @@ error_handler (struct zoran *zr,
        if (zr->JPEG_error != 1) {
                /*
                 * First entry: error just happened during normal operation
-                * 
+                *
                 * In BUZ_MODE_MOTION_COMPRESS:
-                * 
+                *
                 * Possible glitch in TV signal. In this case we should
                 * stop the codec and wait for good quality signal before
                 * restarting it to avoid further problems
-                * 
+                *
                 * In BUZ_MODE_MOTION_DECOMPRESS:
-                * 
+                *
                 * Bad JPEG frame: we have to mark it as processed (codec crashed
                 * and was not able to do it itself), and to remove it from queue.
                 */
index f315203d7105956720fafb54e76914361ce59cd3..f19705cbdb397e591c5781d22ef94fe44532b5bc 100644 (file)
@@ -4,7 +4,7 @@
  * Media Labs LML33/LML33R10.
  *
  * This part handles card-specific data and detection
- * 
+ *
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  *
  * Currently maintained by:
index b2c6e01e39231b53bc1a514ff1914b799466defb..b5a576a37fd26d909dc0e2f492dcc27c93255c03 100644 (file)
@@ -94,7 +94,7 @@
                                V4L2_CAP_VIDEO_CAPTURE |\
                                V4L2_CAP_VIDEO_OUTPUT |\
                                V4L2_CAP_VIDEO_OVERLAY \
-                              )
+                             )
 #endif
 
 #include <asm/byteorder.h>
@@ -165,7 +165,7 @@ const struct zoran_format zoran_formats[] = {
 #endif
                .depth = 16,
                .flags = ZORAN_FORMAT_CAPTURE |
-                        ZORAN_FORMAT_OVERLAY,
+                        ZORAN_FORMAT_OVERLAY,
        }, {
                .name = "Hardware-encoded Motion-JPEG",
                .palette = -1,
@@ -670,7 +670,7 @@ jpg_fbuffer_free (struct file *file)
                                                                       j]))));
                                free_page((unsigned long)
                                          bus_to_virt
-                                                 (le32_to_cpu
+                                                 (le32_to_cpu
                                                   (fh->jpg_buffers.
                                                      buffer[i].
                                                      frag_tab[2 * j])));
@@ -1871,7 +1871,7 @@ zoran_v4l2_buffer_status (struct file        *file,
 
 static int
 zoran_set_norm (struct zoran *zr,
-               int           norm) /* VIDEO_MODE_* */
+               int           norm) /* VIDEO_MODE_* */
 {
        int norm_encoder, on;
 
@@ -2006,9 +2006,9 @@ zoran_set_input (struct zoran *zr,
 
 static int
 zoran_do_ioctl (struct inode *inode,
-               struct file  *file,
-               unsigned int  cmd,
-               void         *arg)
+               struct file  *file,
+               unsigned int  cmd,
+               void         *arg)
 {
        struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
@@ -2095,7 +2095,7 @@ zoran_do_ioctl (struct inode *inode,
                break;
 
                /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
-                * 
+                *
                 * * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
                 * *                                 ^^^^^^^
                 * * The famos BTTV driver has it implemented with a struct video_channel argument
index f0d9b13c3c6c524a6402a7631303b79ef47cd1dd..a00fae90229a84c2236c5bde5346c5778b5ba6d2 100644 (file)
@@ -4,7 +4,7 @@
  * Media Labs LML33/LML33R10.
  *
  * This part handles the procFS entries (/proc/ZORAN[%d])
- * 
+ *
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  *
  * Currently maintained by:
index 8904fc9595555a655ade2a8eb2011d739f51af77..f2d5b1ba448f4b8c8dc4baa9dbe14bcd56e52eeb 100644 (file)
@@ -4,7 +4,7 @@
  * Media Labs LML33/LML33R10.
  *
  * This part handles card-specific data and detection
- * 
+ *
  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
  *
  * Currently maintained by:
index 10130ef67ea7f644d736c0d3daa45c88254f8b4c..62f77584fb859acb30b4dcac559dc07476b1f456 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/types.h>
 #include <linux/wait.h>
 
-/* includes for structures and defines regarding video 
+/* includes for structures and defines regarding video
    #include<linux/videodev.h> */
 
 /* I/O commands, error codes */
@@ -143,8 +143,8 @@ zr36016_readi (struct zr36016 *ptr,
 
 static void
 zr36016_writei (struct zr36016 *ptr,
-               u16             reg,
-               u8              value)
+               u16             reg,
+               u8              value)
 {
        dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name,
                value, reg);
@@ -192,7 +192,7 @@ zr36016_basic_test (struct zr36016 *ptr)
                dprintk(1, "\n");
        }
        // for testing just write 0, then the default value to a register and read
-       // it back in both cases 
+       // it back in both cases
        zr36016_writei(ptr, ZR016I_PAX_LO, 0x00);
        if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) {
                dprintk(1,
@@ -232,17 +232,17 @@ zr36016_basic_test (struct zr36016 *ptr)
 static int zr36016_pushit (struct zr36016 *ptr,
                           u16             startreg,
                           u16             len,
-                           const char     *data)
+                          const char     *data)
 {
-        int i=0;
+       int i=0;
 
-        dprintk(4, "%s: write data block to 0x%04x (len=%d)\n",
+       dprintk(4, "%s: write data block to 0x%04x (len=%d)\n",
                ptr->name, startreg,len);
-        while (i<len) {
-                zr36016_writei(ptr, startreg++,  data[i++]);
-        }
+       while (i<len) {
+               zr36016_writei(ptr, startreg++,  data[i++]);
+       }
 
-        return i;
+       return i;
 }
 #endif
 
index 6699725be60590decc82bc682ebc6861de831684..a6bbd125631c06311c06be7bf175a9a73d8ec9a6 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/types.h>
 #include <linux/wait.h>
 
-/* includes for structures and defines regarding video 
+/* includes for structures and defines regarding video
    #include<linux/videodev.h> */
 
 /* I/O commands, error codes */
@@ -171,7 +171,7 @@ zr36050_wait_end (struct zr36050 *ptr)
 /* =========================================================================
    Local helper function:
 
-   basic test of "connectivity", writes/reads to/from memory the SOF marker 
+   basic test of "connectivity", writes/reads to/from memory the SOF marker
    ========================================================================= */
 
 static int
@@ -218,9 +218,9 @@ zr36050_basic_test (struct zr36050 *ptr)
 
 static int
 zr36050_pushit (struct zr36050 *ptr,
-               u16             startreg,
-               u16             len,
-               const char     *data)
+               u16             startreg,
+               u16             len,
+               const char     *data)
 {
        int i = 0;
 
@@ -345,7 +345,7 @@ static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
 /* ------------------------------------------------------------------------- */
 
 /* SOF (start of frame) segment depends on width, height and sampling ratio
-                         of each color component */
+                        of each color component */
 
 static int
 zr36050_set_sof (struct zr36050 *ptr)
@@ -376,8 +376,8 @@ zr36050_set_sof (struct zr36050 *ptr)
 
 /* ------------------------------------------------------------------------- */
 
-/* SOS (start of scan) segment depends on the used scan components 
-                        of each color component */
+/* SOS (start of scan) segment depends on the used scan components
+                       of each color component */
 
 static int
 zr36050_set_sos (struct zr36050 *ptr)
index 159abfa034d96b4f3df3babd86136dc926a79711..54c9362aa98059879300ab6e7700b041176e688a 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * zr36057.h - zr36057 register offsets
  *
  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
 #define ZR36057_VFEHCR          0x000  /* Video Front End, Horizontal Configuration Register */
 #define ZR36057_VFEHCR_HSPol            (1<<30)
 #define ZR36057_VFEHCR_HStart           10
-#define ZR36057_VFEHCR_HEnd            0
-#define ZR36057_VFEHCR_Hmask           0x3ff
+#define ZR36057_VFEHCR_HEnd            0
+#define ZR36057_VFEHCR_Hmask           0x3ff
 
 #define ZR36057_VFEVCR          0x004  /* Video Front End, Vertical Configuration Register */
 #define ZR36057_VFEVCR_VSPol            (1<<30)
 #define ZR36057_VFEVCR_VStart           10
-#define ZR36057_VFEVCR_VEnd            0
-#define ZR36057_VFEVCR_Vmask           0x3ff
+#define ZR36057_VFEVCR_VEnd            0
+#define ZR36057_VFEVCR_Vmask           0x3ff
 
 #define ZR36057_VFESPFR         0x008  /* Video Front End, Scaler and Pixel Format Register */
 #define ZR36057_VFESPFR_ExtFl           (1<<26)
index d8dd003a7aadef1260da978e8f50f4c3e615ee3e..97c8f9b9dc124d650ec946973a986b05c2137c78 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/types.h>
 #include <linux/wait.h>
 
-/* includes for structures and defines regarding video 
+/* includes for structures and defines regarding video
    #include<linux/videodev.h> */
 
 /* I/O commands, error codes */
@@ -173,7 +173,7 @@ zr36060_wait_end (struct zr36060 *ptr)
 /* =========================================================================
    Local helper function:
 
-   basic test of "connectivity", writes/reads to/from memory the SOF marker 
+   basic test of "connectivity", writes/reads to/from memory the SOF marker
    ========================================================================= */
 
 static int
@@ -208,9 +208,9 @@ zr36060_basic_test (struct zr36060 *ptr)
 
 static int
 zr36060_pushit (struct zr36060 *ptr,
-               u16             startreg,
-               u16             len,
-               const char     *data)
+               u16             startreg,
+               u16             len,
+               const char     *data)
 {
        int i = 0;
 
@@ -335,7 +335,7 @@ static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
 /* ------------------------------------------------------------------------- */
 
 /* SOF (start of frame) segment depends on width, height and sampling ratio
-                         of each color component */
+                        of each color component */
 
 static int
 zr36060_set_sof (struct zr36060 *ptr)
@@ -367,8 +367,8 @@ zr36060_set_sof (struct zr36060 *ptr)
 
 /* ------------------------------------------------------------------------- */
 
-/* SOS (start of scan) segment depends on the used scan components 
-                        of each color component */
+/* SOS (start of scan) segment depends on the used scan components
+                       of each color component */
 
 static int
 zr36060_set_sos (struct zr36060 *ptr)
@@ -385,7 +385,7 @@ zr36060_set_sos (struct zr36060 *ptr)
        for (i = 0; i < NO_OF_COMPONENTS; i++) {
                sos_data[5 + (i * 2)] = i;      // index
                sos_data[6 + (i * 2)] = (zr36060_td[i] << 4) |
-                                       zr36060_ta[i]; // AC/DC tbl.sel.
+                                       zr36060_ta[i]; // AC/DC tbl.sel.
        }
        sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00;      // scan start
        sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3f;
@@ -999,7 +999,7 @@ zr36060_cleanup_module (void)
                dprintk(1,
                        "zr36060: something's wrong - %d codecs left somehow.\n",
                        zr36060_codecs);
-       } 
+       }
 
        /* however, we can't just stay alive */
        videocodec_unregister(&zr36060_codec);
index d4c633b8a7f5cc71420ee3816614907c522f22db..6ac3b67400895c489ca2612d0debbc3813b4adf4 100644 (file)
@@ -70,10 +70,10 @@ MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
 MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(triton1,"i");
-MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i");
-MODULE_PARM(video_nr,"i");
-MODULE_PARM(vbi_nr,"i");
+module_param(triton1, uint, 0);
+module_param_array(cardtype, uint, NULL, 0);
+module_param(video_nr, int, 0);
+module_param(vbi_nr, int, 0);
 
 static int zoran_cards;
 static struct zoran zorans[ZORAN_MAX];
@@ -316,7 +316,7 @@ DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item));
                                item->status = FBUFFER_BUSY;
                                if (!lastitem)
                                        ztv->workqueue = item;
-                               else 
+                               else
                                        lastitem->next = item;
                                lastitem = item;
                        }
@@ -516,7 +516,7 @@ DEBUG(printk(KERN_DEBUG "       %d: clip(%d,%d,%d,%d)\n", i,vp->x,vp->y,vp->widt
        zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
 }
 
-struct tvnorm 
+struct tvnorm
 {
        u16 Wt, Wa, Ht, Ha, HStart, VStart;
 };
@@ -660,7 +660,7 @@ DEBUG(printk(KERN_DEBUG "       Y: scale=0, start=%d, end=%d\n", Hstart, Hend));
                int HorDcm = 64-X;
                int hcrop1 = 2*(Wa-We)/4;
                /*
-                * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi> 
+                * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi>
                 * found the solution to the color phase shift.
                 * See ChangeLog for the full explanation)
                 */
@@ -812,12 +812,12 @@ void zoran_close(struct video_device* dev)
 
        zoran_common_close(ztv);
 
-        /*
-         *      This is sucky but right now I can't find a good way to
-         *      be sure its safe to free the buffer. We wait 5-6 fields
-         *      which is more than sufficient to be sure.
-         */
-        msleep(100);                   /* Wait 1/10th of a second */
+       /*
+        *      This is sucky but right now I can't find a good way to
+        *      be sure its safe to free the buffer. We wait 5-6 fields
+        *      which is more than sufficient to be sure.
+        */
+       msleep(100);                    /* Wait 1/10th of a second */
 
        /* free the allocated framebuffer */
        bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
@@ -1436,7 +1436,7 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
 
         /* Why isn't this in the API?
          * And why doesn't it take a buffer number?
-        case BTTV_FIELDNR: 
+        case BTTV_FIELDNR:
         {
                unsigned long v = ztv->lastfieldnr;
                if (copy_to_user(arg,&v,sizeof(v)))
@@ -1557,12 +1557,12 @@ void vbi_close(struct video_device *dev)
 
        zoran_common_close(ztv);
 
-        /*
-         *      This is sucky but right now I can't find a good way to
-         *      be sure its safe to free the buffer. We wait 5-6 fields
-         *      which is more than sufficient to be sure.
-         */
-        msleep(100);                   /* Wait 1/10th of a second */
+       /*
+        *      This is sucky but right now I can't find a good way to
+        *      be sure its safe to free the buffer. We wait 5-6 fields
+        *      which is more than sufficient to be sure.
+        */
+       msleep(100);                    /* Wait 1/10th of a second */
 
        for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
        {
@@ -1620,7 +1620,7 @@ long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonb
                        write_unlock_irq(&ztv->lock);
                        return -EWOULDBLOCK;
                }
-               
+
                /* mark the unused buffer as wanted */
                unused->status = FBUFFER_BUSY;
                unused->next = 0;
@@ -1671,7 +1671,7 @@ long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonb
        if (count == 2*19*2048) {
                /*
                 * Extreme HACK, old VBI programs expect 2048 points
-                * of data, and we only got 864 orso. Double each 
+                * of data, and we only got 864 orso. Double each
                 * datapoint and clear the rest of the line.
                 * This way we have appear to have a
                 * sample_frequency of 29.5 Mc.
@@ -1956,7 +1956,7 @@ int __init init_zoran(int card)
                zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC);
 
        /* external FL determines TOP frame */
-       zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); 
+       zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC);
 
        /* set HSpol */
        if (ztv->card->hsync_pos)
@@ -2012,7 +2012,7 @@ void release_zoran(int max)
        struct zoran *ztv;
        int i;
 
-       for (i=0;i<max; i++) 
+       for (i=0;i<max; i++)
        {
                ztv = &zorans[i];
 
@@ -2029,7 +2029,7 @@ void release_zoran(int max)
 
                /* free it */
                free_irq(ztv->dev->irq,ztv);
+
                /* unregister i2c_bus */
                i2c_unregister_bus((&ztv->i2c));
 
@@ -2050,7 +2050,7 @@ void __exit zr36120_exit(void)
 int __init zr36120_init(void)
 {
        int     card;
+
        handle_chipset();
        zoran_cards = find_zoran();
        if (zoran_cards<0)
@@ -2063,7 +2063,7 @@ int __init zr36120_init(void)
                        /* only release the zorans we have registered */
                        release_zoran(card);
                        return -EIO;
-               } 
+               }
        }
        return 0;
 }
index 571f8e84b58a2dccc4d5b8b7e505303ab0f04af4..a71e485b0f98b7dc538a9faba5adcbb99e7154ba 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
     zr36120.h - Zoran 36120/36125 based framegrabbers
 
     Copyright (C) 1998-1999 Pauline Middelink (middelin@polyware.nl)
@@ -89,7 +89,7 @@ struct vidinfo {
        ulong*  overlay;        /* kernel addr of overlay mask          */
 };
 
-struct zoran 
+struct zoran
 {
        struct video_device video_dev;
 #define CARD_DEBUG     KERN_DEBUG "%s(%lu): "
@@ -106,7 +106,7 @@ struct zoran
        uint            norm;           /* 0=PAL, 1=NTSC, 2=SECAM       */
        uint            tuner_freq;     /* Current freq in kHz          */
        struct video_picture picture;   /* Current picture params       */
-  
+
        /* videocard details */
        uint            swidth;         /* screen width                 */
        uint            sheight;        /* screen height                */
index 40d4ea898dbc58eba732fa4a4cc7bbc8c54df61a..5a6cca8e8c45df6cf9ff6db950f95523f14f2618 100644 (file)
@@ -419,58 +419,53 @@ void i2o_dump_hrt(struct i2o_controller *c)
                d = (u8 *) (rows + 2);
                state = p[1] << 8 | p[0];
 
-               printk(KERN_DEBUG "TID %04X:[", state & 0xFFF);
+               printk("TID %04X:[", state & 0xFFF);
                state >>= 12;
                if (state & (1 << 0))
-                       printk(KERN_DEBUG "H"); /* Hidden */
+                       printk("H");    /* Hidden */
                if (state & (1 << 2)) {
-                       printk(KERN_DEBUG "P"); /* Present */
+                       printk("P");    /* Present */
                        if (state & (1 << 1))
-                               printk(KERN_DEBUG "C"); /* Controlled */
+                               printk("C");    /* Controlled */
                }
                if (state > 9)
-                       printk(KERN_DEBUG "*"); /* Hard */
+                       printk("*");    /* Hard */
 
-               printk(KERN_DEBUG "]:");
+               printk("]:");
 
                switch (p[3] & 0xFFFF) {
                case 0:
                        /* Adapter private bus - easy */
-                       printk(KERN_DEBUG
-                              "Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
+                       printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
                               d[1] << 8 | d[0], *(u32 *) (d + 4));
                        break;
                case 1:
                        /* ISA bus */
-                       printk(KERN_DEBUG
-                              "ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
+                       printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
                               d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
                        break;
 
                case 2: /* EISA bus */
-                       printk(KERN_DEBUG
-                              "EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+                       printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
                               p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
                        break;
 
                case 3: /* MCA bus */
-                       printk(KERN_DEBUG
-                              "MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
+                       printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
                               d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
                        break;
 
                case 4: /* PCI bus */
-                       printk(KERN_DEBUG
-                              "PCI %d: Bus %d Device %d Function %d", p[2],
+                       printk("PCI %d: Bus %d Device %d Function %d", p[2],
                               d[2], d[1], d[0]);
                        break;
 
                case 0x80:      /* Other */
                default:
-                       printk(KERN_DEBUG "Unsupported bus type.");
+                       printk("Unsupported bus type.");
                        break;
                }
-               printk(KERN_DEBUG "\n");
+               printk("\n");
                rows += length;
        }
 }
index 8d84b045bc83637df61dea3c83467ba63410654e..85e89c77bdea23d36d9f9865a47e6e0ff65be6da 100644 (file)
@@ -87,7 +87,7 @@ struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
 static int dma = 1;
 
 #ifdef MODULE
-MODULE_PARM(dma, "i");
+module_param(dma, bool, 0);
 MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
 #endif
 
index f0f8916da7adf1b9e0d6ad08ba0f8649e96f465f..f988c817e196c9ba3a7185817234158e06aa4398 100644 (file)
@@ -28,7 +28,7 @@
 
 #ifdef CONFIG_MTD_DEBUG
 static int debug = CONFIG_MTD_DEBUG_VERBOSE;
-MODULE_PARM(debug, "i");
+module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
 #undef DEBUG
 #define DEBUG(n, format, arg...) \
@@ -89,17 +89,17 @@ static int mem_type;
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
 MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_PARM(bankwidth, "i");
+module_param(bankwidth, int, 0);
 MODULE_PARM_DESC(bankwidth, "Set bankwidth (1=8 bit, 2=16 bit, default=2)");
-MODULE_PARM(mem_speed, "i");
+module_param(mem_speed, int, 0);
 MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
-MODULE_PARM(force_size, "i");
+module_param(force_size, int, 0);
 MODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)");
-MODULE_PARM(setvpp, "i");
+module_param(setvpp, int, 0);
 MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
-MODULE_PARM(vpp, "i");
+module_param(vpp, int, 0);
 MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
-MODULE_PARM(mem_type, "i");
+module_param(mem_type, int, 0);
 MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
 
 
index 5d11a06ecb2c4f6ce5dfd11081b866d5a7d82e73..d339308539fa828183788c16f22566a5c470c923 100644 (file)
@@ -1096,14 +1096,18 @@ static int __init vortex_eisa_init (void)
        int orig_cards_found = vortex_cards_found;
 
 #ifdef CONFIG_EISA
-       if (eisa_driver_register (&vortex_eisa_driver) >= 0) {
-                       /* Because of the way EISA bus is probed, we cannot assume
-                        * any device have been found when we exit from
-                        * eisa_driver_register (the bus root driver may not be
-                        * initialized yet). So we blindly assume something was
-                        * found, and let the sysfs magic happend... */
-                       
-                       eisa_found = 1;
+       int err;
+
+       err = eisa_driver_register (&vortex_eisa_driver);
+       if (!err) {
+               /*
+                * Because of the way EISA bus is probed, we cannot assume
+                * any device have been found when we exit from
+                * eisa_driver_register (the bus root driver may not be
+                * initialized yet). So we blindly assume something was
+                * found, and let the sysfs magic happend...
+                */
+               eisa_found = 1;
        }
 #endif
        
index 8e538a6d7d9793565e3095c8daa3ad755ec630d5..79bb56b8dcef00fa283284497004c0f7ba3a5dcd 100644 (file)
@@ -829,7 +829,7 @@ static void __devexit a2065_remove_one(struct zorro_dev *z)
 
 static int __init a2065_init_module(void)
 {
-       return zorro_module_init(&a2065_driver);
+       return zorro_register_driver(&a2065_driver);
 }
 
 static void __exit a2065_cleanup_module(void)
index 9fe93acfc8efa5adfcc86aef7c9186108d9b1c41..d1b6b1f794e214ced2db99c3d14c8a68fd9ae480 100644 (file)
@@ -864,7 +864,7 @@ static void __devexit ariadne_remove_one(struct zorro_dev *z)
 
 static int __init ariadne_init_module(void)
 {
-    return zorro_module_init(&ariadne_driver);
+    return zorro_register_driver(&ariadne_driver);
 }
 
 static void __exit ariadne_cleanup_module(void)
index 625184b65e3832922eaee7e02c1bd48ee738e76a..77fe20dbea35054242b94bfd3263e2b56b7050aa 100644 (file)
@@ -31,3 +31,11 @@ config ARM_ETHERH
        help
          If you have an Acorn system with one of these network cards, you
          should say Y to this option if you wish to use it with Linux.
+
+config ARM_AT91_ETHER
+       tristate "AT91RM9200 Ethernet support"
+       depends on NET_ETHERNET && ARM && ARCH_AT91RM9200
+       select MII
+       help
+         If you wish to compile a kernel for the AT91RM9200 and enable
+         ethernet support, then you should always answer Y to this.
index bc263edf06a7aa03024a81c9b7a62d3eb94ec00f..42c95b79c261fa8e06c5cc6715da6dc058f46265 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_ARM_AM79C961A)     += am79c961a.o
 obj-$(CONFIG_ARM_ETHERH)       += etherh.o
 obj-$(CONFIG_ARM_ETHER3)       += ether3.o
 obj-$(CONFIG_ARM_ETHER1)       += ether1.o
+obj-$(CONFIG_ARM_AT91_ETHER)   += at91_ether.o
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
new file mode 100644 (file)
index 0000000..5503dc8
--- /dev/null
@@ -0,0 +1,1110 @@
+/*
+ * Ethernet driver for the Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) 2003 SAN People (Pty) Ltd
+ *
+ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc.
+ * Initial version by Rick Bronson 01/11/2003
+ *
+ * Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker
+ *   (Polaroid Corporation)
+ *
+ * Realtek RTL8201(B)L PHY support by Roman Avramenko <roman@imsystems.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/at91rm9200_emac.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "at91_ether.h"
+
+#define DRV_NAME       "at91_ether"
+#define DRV_VERSION    "1.0"
+
+static struct net_device *at91_dev;
+static struct clk *ether_clk;
+
+/* ..................................................................... */
+
+/*
+ * Read from a EMAC register.
+ */
+static inline unsigned long at91_emac_read(unsigned int reg)
+{
+       void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+
+       return __raw_readl(emac_base + reg);
+}
+
+/*
+ * Write to a EMAC register.
+ */
+static inline void at91_emac_write(unsigned int reg, unsigned long value)
+{
+       void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+
+       __raw_writel(value, emac_base + reg);
+}
+
+/* ........................... PHY INTERFACE ........................... */
+
+/*
+ * Enable the MDIO bit in MAC control register
+ * When not called from an interrupt-handler, access to the PHY must be
+ *  protected by a spinlock.
+ */
+static void enable_mdi(void)
+{
+       unsigned long ctl;
+
+       ctl = at91_emac_read(AT91_EMAC_CTL);
+       at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);    /* enable management port */
+}
+
+/*
+ * Disable the MDIO bit in the MAC control register
+ */
+static void disable_mdi(void)
+{
+       unsigned long ctl;
+
+       ctl = at91_emac_read(AT91_EMAC_CTL);
+       at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);   /* disable management port */
+}
+
+/*
+ * Wait until the PHY operation is complete.
+ */
+static inline void at91_phy_wait(void) {
+       unsigned long timeout = jiffies + 2;
+
+       while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
+               if (time_after(jiffies, timeout)) {
+                       printk("at91_ether: MIO timeout\n");
+                       break;
+               }
+               cpu_relax();
+       }
+}
+
+/*
+ * Write value to the a PHY register
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value)
+{
+       at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
+               | ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA));
+
+       /* Wait until IDLE bit in Network Status register is cleared */
+       at91_phy_wait();
+}
+
+/*
+ * Read value stored in a PHY register.
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
+{
+       at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
+               | ((phy_addr & 0x1f) << 23) | (address << 18));
+
+       /* Wait until IDLE bit in Network Status register is cleared */
+       at91_phy_wait();
+
+       *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
+}
+
+/* ........................... PHY MANAGEMENT .......................... */
+
+/*
+ * Access the PHY to determine the current link speed and mode, and update the
+ * MAC accordingly.
+ * If no link or auto-negotiation is busy, then no changes are made.
+ */
+static void update_linkspeed(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned int bmsr, bmcr, lpa, mac_cfg;
+       unsigned int speed, duplex;
+
+       if (!mii_link_ok(&lp->mii)) {           /* no link */
+               netif_carrier_off(dev);
+               printk(KERN_INFO "%s: Link down.\n", dev->name);
+               return;
+       }
+
+       /* Link up, or auto-negotiation still in progress */
+       read_phy(lp->phy_address, MII_BMSR, &bmsr);
+       read_phy(lp->phy_address, MII_BMCR, &bmcr);
+       if (bmcr & BMCR_ANENABLE) {                             /* AutoNegotiation is enabled */
+               if (!(bmsr & BMSR_ANEGCOMPLETE))
+                       return;                 /* Do nothing - another interrupt generated when negotiation complete */
+
+               read_phy(lp->phy_address, MII_LPA, &lpa);
+               if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
+               else speed = SPEED_10;
+               if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
+               else duplex = DUPLEX_HALF;
+       } else {
+               speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+               duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+       }
+
+       /* Update the MAC */
+       mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
+       if (speed == SPEED_100) {
+               if (duplex == DUPLEX_FULL)              /* 100 Full Duplex */
+                       mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
+               else                                    /* 100 Half Duplex */
+                       mac_cfg |= AT91_EMAC_SPD;
+       } else {
+               if (duplex == DUPLEX_FULL)              /* 10 Full Duplex */
+                       mac_cfg |= AT91_EMAC_FD;
+               else {}                                 /* 10 Half Duplex */
+       }
+       at91_emac_write(AT91_EMAC_CFG, mac_cfg);
+
+       printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+       netif_carrier_on(dev);
+}
+
+/*
+ * Handle interrupts from the PHY
+ */
+static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = (struct net_device *) dev_id;
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned int phy;
+
+       /*
+        * This hander is triggered on both edges, but the PHY chips expect
+        * level-triggering.  We therefore have to check if the PHY actually has
+        * an IRQ pending.
+        */
+       enable_mdi();
+       if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+               read_phy(lp->phy_address, MII_DSINTR_REG, &phy);        /* ack interrupt in Davicom PHY */
+               if (!(phy & (1 << 0)))
+                       goto done;
+       }
+       else if (lp->phy_type == MII_LXT971A_ID) {
+               read_phy(lp->phy_address, MII_ISINTS_REG, &phy);        /* ack interrupt in Intel PHY */
+               if (!(phy & (1 << 2)))
+                       goto done;
+       }
+       else if (lp->phy_type == MII_BCM5221_ID) {
+               read_phy(lp->phy_address, MII_BCMINTR_REG, &phy);       /* ack interrupt in Broadcom PHY */
+               if (!(phy & (1 << 0)))
+                       goto done;
+       }
+       else if (lp->phy_type == MII_KS8721_ID) {
+               read_phy(lp->phy_address, MII_TPISTATUS, &phy);         /* ack interrupt in Micrel PHY */
+               if (!(phy & ((1 << 2) | 1)))
+                       goto done;
+       }
+
+       update_linkspeed(dev);
+
+done:
+       disable_mdi();
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Initialize and enable the PHY interrupt for link-state changes
+ */
+static void enable_phyirq(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned int dsintr, irq_number;
+       int status;
+
+       if (lp->phy_type == MII_RTL8201_ID)     /* RTL8201 does not have an interrupt */
+               return;
+       if (lp->phy_type == MII_DP83847_ID)     /* DP83847 does not have an interrupt */
+               return;
+       if (lp->phy_type == MII_AC101L_ID)      /* AC101L interrupt not supported yet */
+               return;
+
+       irq_number = lp->board_data.phy_irq_pin;
+       status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
+       if (status) {
+               printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
+               return;
+       }
+
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+
+       if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {      /* for Davicom PHY */
+               read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
+               dsintr = dsintr & ~0xf00;               /* clear bits 8..11 */
+               write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
+       }
+       else if (lp->phy_type == MII_LXT971A_ID) {      /* for Intel PHY */
+               read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
+               dsintr = dsintr | 0xf2;                 /* set bits 1, 4..7 */
+               write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
+       }
+       else if (lp->phy_type == MII_BCM5221_ID) {      /* for Broadcom PHY */
+               dsintr = (1 << 15) | ( 1 << 14);
+               write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
+       }
+       else if (lp->phy_type == MII_KS8721_ID) {       /* for Micrel PHY */
+               dsintr = (1 << 10) | ( 1 << 8);
+               write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
+       }
+
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+}
+
+/*
+ * Disable the PHY interrupt
+ */
+static void disable_phyirq(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned int dsintr;
+       unsigned int irq_number;
+
+       if (lp->phy_type == MII_RTL8201_ID)     /* RTL8201 does not have an interrupt */
+               return;
+       if (lp->phy_type == MII_DP83847_ID)     /* DP83847 does not have an interrupt */
+               return;
+       if (lp->phy_type == MII_AC101L_ID)      /* AC101L interrupt not supported yet */
+               return;
+
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+
+       if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {      /* for Davicom PHY */
+               read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
+               dsintr = dsintr | 0xf00;                        /* set bits 8..11 */
+               write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
+       }
+       else if (lp->phy_type == MII_LXT971A_ID) {      /* for Intel PHY */
+               read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
+               dsintr = dsintr & ~0xf2;                        /* clear bits 1, 4..7 */
+               write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
+       }
+       else if (lp->phy_type == MII_BCM5221_ID) {      /* for Broadcom PHY */
+               read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr);
+               dsintr = ~(1 << 14);
+               write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
+       }
+       else if (lp->phy_type == MII_KS8721_ID) {       /* for Micrel PHY */
+               read_phy(lp->phy_address, MII_TPISTATUS, &dsintr);
+               dsintr = ~((1 << 10) | (1 << 8));
+               write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
+       }
+
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+
+       irq_number = lp->board_data.phy_irq_pin;
+       free_irq(irq_number, dev);                      /* Free interrupt handler */
+}
+
+/*
+ * Perform a software reset of the PHY.
+ */
+#if 0
+static void reset_phy(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned int bmcr;
+
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+
+       /* Perform PHY reset */
+       write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
+
+       /* Wait until PHY reset is complete */
+       do {
+               read_phy(lp->phy_address, MII_BMCR, &bmcr);
+       } while (!(bmcr && BMCR_RESET));
+
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+}
+#endif
+
+/* ......................... ADDRESS MANAGEMENT ........................ */
+
+/*
+ * NOTE: Your bootloader must always set the MAC address correctly before
+ * booting into Linux.
+ *
+ * - It must always set the MAC address after reset, even if it doesn't
+ *   happen to access the Ethernet while it's booting.  Some versions of
+ *   U-Boot on the AT91RM9200-DK do not do this.
+ *
+ * - Likewise it must store the addresses in the correct byte order.
+ *   MicroMonitor (uMon) on the CSB337 does this incorrectly (and
+ *   continues to do so, for bug-compatibility).
+ */
+
+static short __init unpack_mac_address(struct net_device *dev, unsigned int hi, unsigned int lo)
+{
+       char addr[6];
+
+       if (machine_is_csb337()) {
+               addr[5] = (lo & 0xff);                  /* The CSB337 bootloader stores the MAC the wrong-way around */
+               addr[4] = (lo & 0xff00) >> 8;
+               addr[3] = (lo & 0xff0000) >> 16;
+               addr[2] = (lo & 0xff000000) >> 24;
+               addr[1] = (hi & 0xff);
+               addr[0] = (hi & 0xff00) >> 8;
+       }
+       else {
+               addr[0] = (lo & 0xff);
+               addr[1] = (lo & 0xff00) >> 8;
+               addr[2] = (lo & 0xff0000) >> 16;
+               addr[3] = (lo & 0xff000000) >> 24;
+               addr[4] = (hi & 0xff);
+               addr[5] = (hi & 0xff00) >> 8;
+       }
+
+       if (is_valid_ether_addr(addr)) {
+               memcpy(dev->dev_addr, &addr, 6);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * Set the ethernet MAC address in dev->dev_addr
+ */
+static void __init get_mac_address(struct net_device *dev)
+{
+       /* Check Specific-Address 1 */
+       if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
+               return;
+       /* Check Specific-Address 2 */
+       if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
+               return;
+       /* Check Specific-Address 3 */
+       if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
+               return;
+       /* Check Specific-Address 4 */
+       if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
+               return;
+
+       printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
+}
+
+/*
+ * Program the hardware MAC address from dev->dev_addr.
+ */
+static void update_mac_address(struct net_device *dev)
+{
+       at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
+       at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
+
+       at91_emac_write(AT91_EMAC_SA2L, 0);
+       at91_emac_write(AT91_EMAC_SA2H, 0);
+}
+
+/*
+ * Store the new hardware address in dev->dev_addr, and update the MAC.
+ */
+static int set_mac_address(struct net_device *dev, void* addr)
+{
+       struct sockaddr *address = addr;
+
+       if (!is_valid_ether_addr(address->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+       update_mac_address(dev);
+
+       printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+       return 0;
+}
+
+static int inline hash_bit_value(int bitnr, __u8 *addr)
+{
+       if (addr[bitnr / 8] & (1 << (bitnr % 8)))
+               return 1;
+       return 0;
+}
+
+/*
+ * The hash address register is 64 bits long and takes up two locations in the memory map.
+ * The least significant bits are stored in EMAC_HSL and the most significant
+ * bits in EMAC_HSH.
+ *
+ * The unicast hash enable and the multicast hash enable bits in the network configuration
+ *  register enable the reception of hash matched frames. The destination address is
+ *  reduced to a 6 bit index into the 64 bit hash register using the following hash function.
+ * The hash function is an exclusive or of every sixth bit of the destination address.
+ *   hash_index[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]
+ *   hash_index[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]
+ *   hash_index[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]
+ *   hash_index[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]
+ *   hash_index[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]
+ *   hash_index[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]
+ * da[0] represents the least significant bit of the first byte received, that is, the multicast/
+ *  unicast indicator, and da[47] represents the most significant bit of the last byte
+ *  received.
+ * If the hash index points to a bit that is set in the hash register then the frame will be
+ *  matched according to whether the frame is multicast or unicast.
+ * A multicast match will be signalled if the multicast hash enable bit is set, da[0] is 1 and
+ *  the hash index points to a bit set in the hash register.
+ * A unicast match will be signalled if the unicast hash enable bit is set, da[0] is 0 and the
+ *  hash index points to a bit set in the hash register.
+ * To receive all multicast frames, the hash register should be set with all ones and the
+ *  multicast hash enable bit should be set in the network configuration register.
+ */
+
+/*
+ * Return the hash index value for the specified address.
+ */
+static int hash_get_index(__u8 *addr)
+{
+       int i, j, bitval;
+       int hash_index = 0;
+
+       for (j = 0; j < 6; j++) {
+               for (i = 0, bitval = 0; i < 8; i++)
+                       bitval ^= hash_bit_value(i*6 + j, addr);
+
+               hash_index |= (bitval << j);
+       }
+
+        return hash_index;
+}
+
+/*
+ * Add multicast addresses to the internal multicast-hash table.
+ */
+static void at91ether_sethashtable(struct net_device *dev)
+{
+       struct dev_mc_list *curr;
+       unsigned long mc_filter[2];
+       unsigned int i, bitnr;
+
+       mc_filter[0] = mc_filter[1] = 0;
+
+       curr = dev->mc_list;
+       for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
+               if (!curr) break;       /* unexpected end of list */
+
+               bitnr = hash_get_index(curr->dmi_addr);
+               mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+       }
+
+       at91_emac_write(AT91_EMAC_HSH, mc_filter[0]);
+       at91_emac_write(AT91_EMAC_HSL, mc_filter[1]);
+}
+
+/*
+ * Enable/Disable promiscuous and multicast modes.
+ */
+static void at91ether_set_rx_mode(struct net_device *dev)
+{
+       unsigned long cfg;
+
+       cfg = at91_emac_read(AT91_EMAC_CFG);
+
+       if (dev->flags & IFF_PROMISC)                   /* Enable promiscuous mode */
+               cfg |= AT91_EMAC_CAF;
+       else if (dev->flags & (~IFF_PROMISC))           /* Disable promiscuous mode */
+               cfg &= ~AT91_EMAC_CAF;
+
+       if (dev->flags & IFF_ALLMULTI) {                /* Enable all multicast mode */
+               at91_emac_write(AT91_EMAC_HSH, -1);
+               at91_emac_write(AT91_EMAC_HSL, -1);
+               cfg |= AT91_EMAC_MTI;
+       } else if (dev->mc_count > 0) {                 /* Enable specific multicasts */
+               at91ether_sethashtable(dev);
+               cfg |= AT91_EMAC_MTI;
+       } else if (dev->flags & (~IFF_ALLMULTI)) {      /* Disable all multicast mode */
+               at91_emac_write(AT91_EMAC_HSH, 0);
+               at91_emac_write(AT91_EMAC_HSL, 0);
+               cfg &= ~AT91_EMAC_MTI;
+       }
+
+       at91_emac_write(AT91_EMAC_CFG, cfg);
+}
+
+
+/* ......................... ETHTOOL SUPPORT ........................... */
+
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+       unsigned int value;
+
+       read_phy(phy_id, location, &value);
+       return value;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+       write_phy(phy_id, location, value);
+}
+
+static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       int ret;
+
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+
+       ret = mii_ethtool_gset(&lp->mii, cmd);
+
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+
+       if (lp->phy_media == PORT_FIBRE) {              /* override media type since mii.c doesn't know */
+               cmd->supported = SUPPORTED_FIBRE;
+               cmd->port = PORT_FIBRE;
+       }
+
+       return ret;
+}
+
+static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       int ret;
+
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+
+       ret = mii_ethtool_sset(&lp->mii, cmd);
+
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+
+       return ret;
+}
+
+static int at91ether_nwayreset(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       int ret;
+
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+
+       ret = mii_nway_restart(&lp->mii);
+
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+
+       return ret;
+}
+
+static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+}
+
+static struct ethtool_ops at91ether_ethtool_ops = {
+       .get_settings   = at91ether_get_settings,
+       .set_settings   = at91ether_set_settings,
+       .get_drvinfo    = at91ether_get_drvinfo,
+       .nway_reset     = at91ether_nwayreset,
+       .get_link       = ethtool_op_get_link,
+};
+
+
+/* ................................ MAC ................................ */
+
+/*
+ * Initialize and start the Receiver and Transmit subsystems
+ */
+static void at91ether_start(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       struct recv_desc_bufs *dlist, *dlist_phys;
+       int i;
+       unsigned long ctl;
+
+       dlist = lp->dlist;
+       dlist_phys = lp->dlist_phys;
+
+       for (i = 0; i < MAX_RX_DESCR; i++) {
+               dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0];
+               dlist->descriptors[i].size = 0;
+       }
+
+       /* Set the Wrap bit on the last descriptor */
+       dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP;
+
+       /* Reset buffer index */
+       lp->rxBuffIndex = 0;
+
+       /* Program address of descriptor list in Rx Buffer Queue register */
+       at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
+
+       /* Enable Receive and Transmit */
+       ctl = at91_emac_read(AT91_EMAC_CTL);
+       at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
+}
+
+/*
+ * Open the ethernet interface
+ */
+static int at91ether_open(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned long ctl;
+
+        if (!is_valid_ether_addr(dev->dev_addr))
+               return -EADDRNOTAVAIL;
+
+       clk_enable(ether_clk);                  /* Re-enable Peripheral clock */
+
+       /* Clear internal statistics */
+       ctl = at91_emac_read(AT91_EMAC_CTL);
+       at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
+
+       /* Update the MAC address (incase user has changed it) */
+       update_mac_address(dev);
+
+       /* Enable PHY interrupt */
+       enable_phyirq(dev);
+
+       /* Enable MAC interrupts */
+       at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+                               | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+                               | AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+       /* Determine current link speed */
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+       update_linkspeed(dev);
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+
+       at91ether_start(dev);
+       netif_start_queue(dev);
+       return 0;
+}
+
+/*
+ * Close the interface
+ */
+static int at91ether_close(struct net_device *dev)
+{
+       unsigned long ctl;
+
+       /* Disable Receiver and Transmitter */
+       ctl = at91_emac_read(AT91_EMAC_CTL);
+       at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
+
+       /* Disable PHY interrupt */
+       disable_phyirq(dev);
+
+       /* Disable MAC interrupts */
+       at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+                               | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+                               | AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+       netif_stop_queue(dev);
+
+       clk_disable(ether_clk);                 /* Disable Peripheral clock */
+
+       return 0;
+}
+
+/*
+ * Transmit packet.
+ */
+static int at91ether_tx(struct sk_buff *skb, struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+
+       if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
+               netif_stop_queue(dev);
+
+               /* Store packet information (to free when Tx completed) */
+               lp->skb = skb;
+               lp->skb_length = skb->len;
+               lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
+               lp->stats.tx_bytes += skb->len;
+
+               /* Set address of the data in the Transmit Address register */
+               at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
+               /* Set length of the packet in the Transmit Control register */
+               at91_emac_write(AT91_EMAC_TCR, skb->len);
+
+               dev->trans_start = jiffies;
+       } else {
+               printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n");
+               return 1;       /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb)
+                               on this skb, he also reports -ENETDOWN and printk's, so either
+                               we free and return(0) or don't free and return 1 */
+       }
+
+       return 0;
+}
+
+/*
+ * Update the current statistics from the internal statistics registers.
+ */
+static struct net_device_stats *at91ether_stats(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       int ale, lenerr, seqe, lcol, ecol;
+
+       if (netif_running(dev)) {
+               lp->stats.rx_packets += at91_emac_read(AT91_EMAC_OK);           /* Good frames received */
+               ale = at91_emac_read(AT91_EMAC_ALE);
+               lp->stats.rx_frame_errors += ale;                               /* Alignment errors */
+               lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
+               lp->stats.rx_length_errors += lenerr;                           /* Excessive Length or Undersize Frame error */
+               seqe = at91_emac_read(AT91_EMAC_SEQE);
+               lp->stats.rx_crc_errors += seqe;                                /* CRC error */
+               lp->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC);     /* Receive buffer not available */
+               lp->stats.rx_errors += (ale + lenerr + seqe
+                       + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
+
+               lp->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA);          /* Frames successfully transmitted */
+               lp->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE);      /* Transmit FIFO underruns */
+               lp->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE);   /* Carrier Sense errors */
+               lp->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
+
+               lcol = at91_emac_read(AT91_EMAC_LCOL);
+               ecol = at91_emac_read(AT91_EMAC_ECOL);
+               lp->stats.tx_window_errors += lcol;                     /* Late collisions */
+               lp->stats.tx_aborted_errors += ecol;                    /* 16 collisions */
+
+               lp->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
+       }
+       return &lp->stats;
+}
+
+/*
+ * Extract received frame from buffer descriptors and sent to upper layers.
+ * (Called from interrupt context)
+ */
+static void at91ether_rx(struct net_device *dev)
+{
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       struct recv_desc_bufs *dlist;
+       unsigned char *p_recv;
+       struct sk_buff *skb;
+       unsigned int pktlen;
+
+       dlist = lp->dlist;
+       while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) {
+               p_recv = dlist->recv_buf[lp->rxBuffIndex];
+               pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff;      /* Length of frame including FCS */
+               skb = alloc_skb(pktlen + 2, GFP_ATOMIC);
+               if (skb != NULL) {
+                       skb_reserve(skb, 2);
+                       memcpy(skb_put(skb, pktlen), p_recv, pktlen);
+
+                       skb->dev = dev;
+                       skb->protocol = eth_type_trans(skb, dev);
+                       skb->len = pktlen;
+                       dev->last_rx = jiffies;
+                       lp->stats.rx_bytes += pktlen;
+                       netif_rx(skb);
+               }
+               else {
+                       lp->stats.rx_dropped += 1;
+                       printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+               }
+
+               if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST)
+                       lp->stats.multicast++;
+
+               dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE;    /* reset ownership bit */
+               if (lp->rxBuffIndex == MAX_RX_DESCR-1)                          /* wrap after last buffer */
+                       lp->rxBuffIndex = 0;
+               else
+                       lp->rxBuffIndex++;
+       }
+}
+
+/*
+ * MAC interrupt handler
+ */
+static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = (struct net_device *) dev_id;
+       struct at91_private *lp = (struct at91_private *) dev->priv;
+       unsigned long intstatus, ctl;
+
+       /* MAC Interrupt Status register indicates what interrupts are pending.
+          It is automatically cleared once read. */
+       intstatus = at91_emac_read(AT91_EMAC_ISR);
+
+       if (intstatus & AT91_EMAC_RCOM)         /* Receive complete */
+               at91ether_rx(dev);
+
+       if (intstatus & AT91_EMAC_TCOM) {               /* Transmit complete */
+               /* The TCOM bit is set even if the transmission failed. */
+               if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY))
+                       lp->stats.tx_errors += 1;
+
+               if (lp->skb) {
+                       dev_kfree_skb_irq(lp->skb);
+                       lp->skb = NULL;
+                       dma_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, DMA_TO_DEVICE);
+               }
+               netif_wake_queue(dev);
+       }
+
+       /* Work-around for Errata #11 */
+       if (intstatus & AT91_EMAC_RBNA) {
+               ctl = at91_emac_read(AT91_EMAC_CTL);
+               at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
+               at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
+       }
+
+       if (intstatus & AT91_EMAC_ROVR)
+               printk("%s: ROVR error\n", dev->name);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Initialize the ethernet interface
+ */
+static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev)
+{
+       struct at91_eth_data *board_data = pdev->dev.platform_data;
+       struct net_device *dev;
+       struct at91_private *lp;
+       unsigned int val;
+       int res;
+
+       if (at91_dev)                   /* already initialized */
+               return 0;
+
+       dev = alloc_etherdev(sizeof(struct at91_private));
+       if (!dev)
+               return -ENOMEM;
+
+       dev->base_addr = AT91_VA_BASE_EMAC;
+       dev->irq = AT91_ID_EMAC;
+       SET_MODULE_OWNER(dev);
+
+       /* Install the interrupt handler */
+       if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
+               free_netdev(dev);
+               return -EBUSY;
+       }
+
+       /* Allocate memory for DMA Receive descriptors */
+       lp = (struct at91_private *)dev->priv;
+       lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL);
+       if (lp->dlist == NULL) {
+               free_irq(dev->irq, dev);
+               free_netdev(dev);
+               return -ENOMEM;
+       }
+       lp->board_data = *board_data;
+       platform_set_drvdata(pdev, dev);
+
+       spin_lock_init(&lp->lock);
+
+       ether_setup(dev);
+       dev->open = at91ether_open;
+       dev->stop = at91ether_close;
+       dev->hard_start_xmit = at91ether_tx;
+       dev->get_stats = at91ether_stats;
+       dev->set_multicast_list = at91ether_set_rx_mode;
+       dev->set_mac_address = set_mac_address;
+       dev->ethtool_ops = &at91ether_ethtool_ops;
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       get_mac_address(dev);           /* Get ethernet address and store it in dev->dev_addr */
+       update_mac_address(dev);        /* Program ethernet address into MAC */
+
+       at91_emac_write(AT91_EMAC_CTL, 0);
+
+       if (lp->board_data.is_rmii)
+               at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
+       else
+               at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
+
+       /* Perform PHY-specific initialization */
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+       if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+               read_phy(phy_address, MII_DSCR_REG, &val);
+               if ((val & (1 << 10)) == 0)                     /* DSCR bit 10 is 0 -- fiber mode */
+                       lp->phy_media = PORT_FIBRE;
+       } else if (machine_is_csb337()) {
+               /* mix link activity status into LED2 link state */
+               write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
+       }
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+
+       lp->mii.dev = dev;              /* Support for ethtool */
+       lp->mii.mdio_read = mdio_read;
+       lp->mii.mdio_write = mdio_write;
+
+       lp->phy_type = phy_type;        /* Type of PHY connected */
+       lp->phy_address = phy_address;  /* MDI address of PHY */
+
+       /* Register the network interface */
+       res = register_netdev(dev);
+       if (res) {
+               free_irq(dev->irq, dev);
+               free_netdev(dev);
+               dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+               return res;
+       }
+       at91_dev = dev;
+
+       /* Determine current link speed */
+       spin_lock_irq(&lp->lock);
+       enable_mdi();
+       update_linkspeed(dev);
+       disable_mdi();
+       spin_unlock_irq(&lp->lock);
+       netif_carrier_off(dev);         /* will be enabled in open() */
+
+       /* Display ethernet banner */
+       printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
+               dev->name, (uint) dev->base_addr, dev->irq,
+               at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+               at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+       if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
+               printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+       else if (phy_type == MII_LXT971A_ID)
+               printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
+       else if (phy_type == MII_RTL8201_ID)
+               printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
+       else if (phy_type == MII_BCM5221_ID)
+               printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
+       else if (phy_type == MII_DP83847_ID)
+               printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
+       else if (phy_type == MII_AC101L_ID)
+               printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
+       else if (phy_type == MII_KS8721_ID)
+               printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
+
+       return 0;
+}
+
+/*
+ * Detect MAC and PHY and perform initialization
+ */
+static int __init at91ether_probe(struct platform_device *pdev)
+{
+       unsigned int phyid1, phyid2;
+       int detected = -1;
+       unsigned long phy_id;
+       unsigned short phy_address = 0;
+
+       ether_clk = clk_get(&pdev->dev, "ether_clk");
+       if (!ether_clk) {
+               printk(KERN_ERR "at91_ether: no clock defined\n");
+               return -ENODEV;
+       }
+       clk_enable(ether_clk);                                  /* Enable Peripheral clock */
+
+       while ((detected != 0) && (phy_address < 32)) {
+               /* Read the PHY ID registers */
+               enable_mdi();
+               read_phy(phy_address, MII_PHYSID1, &phyid1);
+               read_phy(phy_address, MII_PHYSID2, &phyid2);
+               disable_mdi();
+
+               phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
+               switch (phy_id) {
+                       case MII_DM9161_ID:             /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
+                       case MII_DM9161A_ID:            /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
+                       case MII_LXT971A_ID:            /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
+                       case MII_RTL8201_ID:            /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
+                       case MII_BCM5221_ID:            /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
+                       case MII_DP83847_ID:            /* National Semiconductor DP83847:  */
+                       case MII_AC101L_ID:             /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
+                       case MII_KS8721_ID:             /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+                               detected = at91ether_setup(phy_id, phy_address, pdev);
+                               break;
+               }
+
+               phy_address++;
+       }
+
+       clk_disable(ether_clk);                                 /* Disable Peripheral clock */
+
+       return detected;
+}
+
+static int __devexit at91ether_remove(struct platform_device *pdev)
+{
+       struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+
+       unregister_netdev(at91_dev);
+       free_irq(at91_dev->irq, at91_dev);
+       dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+       clk_put(ether_clk);
+
+       free_netdev(at91_dev);
+       at91_dev = NULL;
+       return 0;
+}
+
+static struct platform_driver at91ether_driver = {
+       .probe          = at91ether_probe,
+       .remove         = __devexit_p(at91ether_remove),
+       /* FIXME:  support suspend and resume */
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91ether_init(void)
+{
+       return platform_driver_register(&at91ether_driver);
+}
+
+static void __exit at91ether_exit(void)
+{
+       platform_driver_unregister(&at91ether_driver);
+}
+
+module_init(at91ether_init)
+module_exit(at91ether_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver");
+MODULE_AUTHOR("Andrew Victor");
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
new file mode 100644 (file)
index 0000000..9885735
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Ethernet driver for the Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) SAN People (Pty) Ltd
+ *
+ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc.
+ * Initial version by Rick Bronson.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AT91_ETHERNET
+#define AT91_ETHERNET
+
+
+/* Davicom 9161 PHY */
+#define MII_DM9161_ID  0x0181b880
+#define MII_DM9161A_ID 0x0181b8a0
+
+/* Davicom specific registers */
+#define MII_DSCR_REG   16
+#define MII_DSCSR_REG  17
+#define MII_DSINTR_REG 21
+
+/* Intel LXT971A PHY */
+#define MII_LXT971A_ID 0x001378E0
+
+/* Intel specific registers */
+#define MII_ISINTE_REG 18
+#define MII_ISINTS_REG 19
+#define MII_LEDCTRL_REG        20
+
+/* Realtek RTL8201 PHY */
+#define MII_RTL8201_ID 0x00008200
+
+/* Broadcom BCM5221 PHY */
+#define MII_BCM5221_ID 0x004061e0
+
+/* Broadcom specific registers */
+#define MII_BCMINTR_REG        26
+
+/* National Semiconductor DP83847 */
+#define MII_DP83847_ID 0x20005c30
+
+/* Altima AC101L PHY */
+#define MII_AC101L_ID  0x00225520
+
+/* Micrel KS8721 PHY */
+#define MII_KS8721_ID  0x00221610
+
+/* ........................................................................ */
+
+#define MAX_RBUFF_SZ   0x600           /* 1518 rounded up */
+#define MAX_RX_DESCR   9               /* max number of receive buffers */
+
+#define EMAC_DESC_DONE 0x00000001      /* bit for if DMA is done */
+#define EMAC_DESC_WRAP 0x00000002      /* bit for wrap */
+
+#define EMAC_BROADCAST 0x80000000      /* broadcast address */
+#define EMAC_MULTICAST 0x40000000      /* multicast address */
+#define EMAC_UNICAST   0x20000000      /* unicast address */
+
+struct rbf_t
+{
+       unsigned int addr;
+       unsigned long size;
+};
+
+struct recv_desc_bufs
+{
+       struct rbf_t descriptors[MAX_RX_DESCR];         /* must be on sizeof (rbf_t) boundary */
+       char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ];      /* must be on long boundary */
+};
+
+struct at91_private
+{
+       struct net_device_stats stats;
+       struct mii_if_info mii;                 /* ethtool support */
+       struct at91_eth_data board_data;        /* board-specific configuration */
+
+       /* PHY */
+       unsigned long phy_type;                 /* type of PHY (PHY_ID) */
+       spinlock_t lock;                        /* lock for MDI interface */
+       short phy_media;                        /* media interface type */
+       unsigned short phy_address;             /* 5-bit MDI address of PHY (0..31) */
+
+       /* Transmit */
+       struct sk_buff *skb;                    /* holds skb until xmit interrupt completes */
+       dma_addr_t skb_physaddr;                /* phys addr from pci_map_single */
+       int skb_length;                         /* saved skb length for pci_unmap_single */
+
+       /* Receive */
+       int rxBuffIndex;                        /* index into receive descriptor list */
+       struct recv_desc_bufs *dlist;           /* descriptor list address */
+       struct recv_desc_bufs *dlist_phys;      /* descriptor list physical address */
+};
+
+#endif
index 0095384ff45420c1cd04111fa04ea35a3d365865..5e5f80b99b9e497c70f4f6a78d1d0a396ba5872f 100644 (file)
@@ -123,7 +123,7 @@ static char version[] =
  * Global variable 'bionet_debug'. Can be set at load time by 'insmod'
  */
 unsigned int bionet_debug = NET_DEBUG;
-MODULE_PARM(bionet_debug, "i");
+module_param(bionet_debug, int, 0);
 MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
 MODULE_LICENSE("GPL");
 
index 8b997809f9de2db86a31a9db66399c7ceb1430a0..d6039e62d832ebf7858648a097841c4b9edf5bbb 100644 (file)
@@ -119,7 +119,7 @@ static char *version =
  * Global variable 'pamsnet_debug'. Can be set at load time by 'insmod'
  */
 unsigned int pamsnet_debug = NET_DEBUG;
-MODULE_PARM(pamsnet_debug, "i");
+module_param(pamsnet_debug, int, 0);
 MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)");
 MODULE_LICENSE("GPL");
 
index e01b6a78ec6330115ce08a104498aeb3dbf91194..442b2cbeb58a739507efca61d12f69139486d064 100644 (file)
@@ -78,7 +78,7 @@ static int lance_debug = LANCE_DEBUG;
 #else
 static int lance_debug = 1;
 #endif
-MODULE_PARM(lance_debug, "i");
+module_param(lance_debug, int, 0);
 MODULE_PARM_DESC(lance_debug, "atarilance debug level (0-3)");
 MODULE_LICENSE("GPL");
 
index 8f1573e658a5f7f808778ab3375be5b9602945b1..ac48f7543500b7c53d5099383fa26c83c247a45e 100644 (file)
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
+static int cassini_debug = -1; /* -1 == use CAS_DEF_MSG_ENABLE as value */
+static int link_mode;
+
 MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)");
 MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver");
 MODULE_LICENSE("GPL");
-MODULE_PARM(cassini_debug, "i");
+module_param(cassini_debug, int, 0);
 MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value");
-MODULE_PARM(link_mode, "i");
+module_param(link_mode, int, 0);
 MODULE_PARM_DESC(link_mode, "default link mode");
 
 /*
@@ -209,7 +212,7 @@ MODULE_PARM_DESC(link_mode, "default link mode");
  * Value in seconds, for user input.
  */
 static int linkdown_timeout = DEFAULT_LINKDOWN_TIMEOUT;
-MODULE_PARM(linkdown_timeout, "i");
+module_param(linkdown_timeout, int, 0);
 MODULE_PARM_DESC(linkdown_timeout,
 "min reset interval in sec. for PCS linkdown issue; disabled if not positive");
 
@@ -221,8 +224,6 @@ MODULE_PARM_DESC(linkdown_timeout,
 static int link_transition_timeout;
 
 
-static int cassini_debug = -1; /* -1 == use CAS_DEF_MSG_ENABLE as value */
-static int link_mode;
 
 static u16 link_modes[] __devinitdata = {
        BMCR_ANENABLE,                   /* 0 : autoneg */
index 349ebe783ed6b87892d242e679e5a9b210a51696..7fe2638ae06d9b64748a0997cdf66f157a7280b3 100644 (file)
@@ -124,7 +124,7 @@ MODULE_LICENSE("GPL");
 
 static int dflt_msg_enable = DFLT_MSG_ENABLE;
 
-MODULE_PARM(dflt_msg_enable, "i");
+module_param(dflt_msg_enable, int, 0);
 MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T1 message enable bitmap");
 
 
index 32d13166c6e8007b5f9de3c0330d8508445377d1..e175d4876682d8705023ac84bd4c7d35afa7e129 100644 (file)
@@ -1551,7 +1551,7 @@ MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-
 static int __init dgrs_init_module (void)
 {
        int     i;
-       int     cardcount = 0;
+       int     err;
 
        /*
         *      Command line variable overrides
@@ -1593,13 +1593,13 @@ static int __init dgrs_init_module (void)
         *      Find and configure all the cards
         */
 #ifdef CONFIG_EISA
-       cardcount = eisa_driver_register(&dgrs_eisa_driver);
-       if (cardcount < 0)
-               return cardcount;
+       err = eisa_driver_register(&dgrs_eisa_driver);
+       if (err)
+               return err;
 #endif
-       cardcount = pci_register_driver(&dgrs_pci_driver);
-       if (cardcount)
-               return cardcount;
+       err = pci_register_driver(&dgrs_pci_driver);
+       if (err)
+               return err;
        return 0;
 }
 
index b4f3a9f8a535ac0814920057f9eaf6a134ead9c9..7e433809713968b4f719ff280df017f436e073c7 100644 (file)
@@ -55,11 +55,11 @@ MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
 MODULE_DESCRIPTION("Motorola 8xx FEC ethernet driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(fec_8xx_debug, "i");
+int fec_8xx_debug = -1;                /* -1 == use FEC_8XX_DEF_MSG_ENABLE as value */
+module_param(fec_8xx_debug, int, 0);
 MODULE_PARM_DESC(fec_8xx_debug,
                 "FEC 8xx bitmapped debugging message enable value");
 
-int fec_8xx_debug = -1;                /* -1 == use FEC_8XX_DEF_MSG_ENABLE as value */
 
 /*************************************************/
 
index f5d49a1106545ca68c00840137434d20b92c0dc2..196298f33db8b31bb950ac30c855aa70204564bd 100644 (file)
@@ -58,11 +58,11 @@ MODULE_DESCRIPTION("Freescale Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
-MODULE_PARM(fs_enet_debug, "i");
+int fs_enet_debug = -1;                /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
+module_param(fs_enet_debug, int, 0);
 MODULE_PARM_DESC(fs_enet_debug,
                 "Freescale bitmapped debugging message enable value");
 
-int fs_enet_debug = -1;                /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
 
 static void fs_set_multicast_list(struct net_device *dev)
 {
index 5958a63147230620d4ddf461c26455e2188d18b6..2d24354046144870370d26c054fea3b6a7e57774 100644 (file)
@@ -114,8 +114,8 @@ static int max_interrupt_work = 32;
 
 static char mac0[18] = "00.02.03.04.05.06";
 static char mac1[18] = "00.01.02.03.04.05";
-MODULE_PARM(mac0, "c18");
-MODULE_PARM(mac1, "c18");
+module_param_string(mac0, mac0, 18, 0);
+module_param_string(mac1, mac0, 18, 0);
 MODULE_PARM_DESC(mac0, "MAC address for GT96100 ethernet port 0");
 MODULE_PARM_DESC(mac1, "MAC address for GT96100 ethernet port 1");
 
index c8dc40214a087f752a0be4ce7b644e7c24fc223c..79a8fbcf5f93bb4881c43a06094af73064a0450d 100644 (file)
@@ -280,7 +280,7 @@ static unsigned long rand;
 
 MODULE_AUTHOR("Klaus Kudielka");
 MODULE_DESCRIPTION("Driver for high-speed SCC boards");
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
+module_param_array(io, int, NULL, 0);
 MODULE_LICENSE("GPL");
 
 static void __exit dmascc_exit(void)
index dc5e9d59deede332e84caa2241c22c255cf2b7a3..d81a8e1eeb8d5f807fce83f5a99ef04fefd755cf 100644 (file)
@@ -1012,7 +1012,7 @@ static void __exit mkiss_exit_driver(void)
 
 MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
 MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
-MODULE_PARM(crc_force, "i");
+module_param(crc_force, int, 0);
 MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_AX25);
index d8410634bcafc078ad4da1f6979fe1577a842b81..68569346460528654a5491abb34ad83a6c64bca2 100644 (file)
@@ -217,7 +217,7 @@ static int hplance_close(struct net_device *dev)
 
 int __init hplance_init_module(void)
 {
-       return dio_module_init(&hplance_driver);
+       return dio_register_driver(&hplance_driver);
 }
 
 void __exit hplance_cleanup_module(void)
index 6e0ca7340a8fd9126d2837e94ddf4730e7e214e3..d9fb8e74e631d7e019e9d61fb30a04412b3c3be9 100644 (file)
@@ -242,7 +242,7 @@ static void __devexit hydra_remove_one(struct zorro_dev *z)
 
 static int __init hydra_init_module(void)
 {
-    return zorro_module_init(&hydra_driver);
+    return zorro_register_driver(&hydra_driver);
 }
 
 static void __exit hydra_cleanup_module(void)
index 6070195b87bd711645840acc3536241277e69341..98fa5319e5cca369b06a8c409897bc0522c91606 100644 (file)
@@ -1118,9 +1118,9 @@ static void __exit irport_cleanup(void)
        }
 }
 
-MODULE_PARM(io, "1-4i");
+module_param_array(io, int, NULL, 0);
 MODULE_PARM_DESC(io, "Base I/O addresses");
-MODULE_PARM(irq, "1-4i");
+module_param_array(irq, int, NULL, 0);
 MODULE_PARM_DESC(irq, "IRQ lines");
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
index f7b7238d8352ed09a1652721aa8848282acdd617..957888de3d7e8578c0f05ad4616a4d688967a26e 100644 (file)
@@ -177,7 +177,7 @@ static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
 MODULE_AUTHOR("Richard Hirst");
 MODULE_DESCRIPTION("i82596 driver");
 MODULE_LICENSE("GPL");
-MODULE_PARM(i596_debug, "i");
+module_param(i596_debug, int, 0);
 MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
@@ -1520,9 +1520,9 @@ static void set_multicast_list(struct net_device *dev)
        }
 }
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
 static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
 
 static int num_drivers;
 static struct net_device *netdevs[MAX_DRIVERS];
index f65b0db111b8d5b49ac30058b68cb3a9b99caf7a..cd3c9a5a98b25be77691af97816ab53a45cf06bb 100644 (file)
@@ -629,7 +629,7 @@ static int set_mac_address(struct net_device *dev, void *addr)
 static struct net_device *dev_cs89x0;
 static int debug;
 
-MODULE_PARM(debug, "i");
+module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
 MODULE_LICENSE("GPL");
 
index 2a5add257b8f32fab854367946d0eccef51e1591..77792b28602787e342f8b9e1ea7bfc1aed5f9db6 100644 (file)
@@ -1042,7 +1042,7 @@ static void __exit mace_cleanup(void)
 
 MODULE_AUTHOR("Paul Mackerras");
 MODULE_DESCRIPTION("PowerMac MACE driver.");
-MODULE_PARM(port_aaui, "i");
+module_param(port_aaui, int, 0);
 MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)");
 MODULE_LICENSE("GPL");
 
index e23655f5049fa340ba432fc3ecb4fb90b1bd3d1e..d644bf3a933c7d4d7e199107063556f4073ca7f7 100644 (file)
@@ -62,7 +62,7 @@ MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver");
 
 #ifdef HAVE_TX_TIMEOUT
 static int timeout = TX_TIMEOUT;
-MODULE_PARM(timeout, "i");
+module_param(timeout, int, 0);
 #endif
 
 /*
index aaebd28a192023501af8f8f11c449d33568aaaa4..7ea3d596ac3be35beafe21a9ba5f8aa60c7e5553 100644 (file)
@@ -601,9 +601,9 @@ static int io[MAX_NE_CARDS];
 static int irq[MAX_NE_CARDS];
 static int bad[MAX_NE_CARDS];  /* 0xbad = bad sig or no reset ack */
 
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
-MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
+module_param_array(io, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+module_param_array(bad, int, NULL, 0);
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s)");
 MODULE_DESCRIPTION("H8/300 NE2000 Ethernet driver");
index e3ebb5803b023c62f0fd0a940b4d52d3696c9690..d11821dd86edbf94015c7143e048d4da5b5bfde7 100644 (file)
@@ -117,7 +117,7 @@ enum ne2k_pci_chipsets {
 };
 
 
-static const struct {
+static struct {
        char *name;
        int flags;
 } pci_clone_list[] __devinitdata = {
index 2ab01a5d1d229a0b8c16263055b7148f6a0f9a62..a68bf474f6ed8f05b4c24721b1a64fca026f8aa6 100644 (file)
@@ -766,8 +766,8 @@ static void ni5010_show_registers(struct net_device *dev)
 #ifdef MODULE
 static struct net_device *dev_ni5010;
 
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
+module_param(io, int, 0);
+module_param(irq, int, 0);
 MODULE_PARM_DESC(io, "ni5010 I/O base address");
 MODULE_PARM_DESC(irq, "ni5010 IRQ number");
 
index 01bdb23340584bf6576d9a63b90f5a92645110df..d4c0002b43db658f8099891afcc5f18bad53620a 100644 (file)
@@ -71,7 +71,7 @@ static int lance_debug = LANCE_DEBUG;
 #else
 static int lance_debug = 1;
 #endif
-MODULE_PARM(lance_debug, "i");
+module_param(lance_debug, int, 0);
 MODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)");
 MODULE_LICENSE("GPL");
 
index 6a1033ec06cf9cec5c2cd29376a11c9f384687df..fd17aa8491b68e26968d85e44bbf13f0af4d878c 100644 (file)
@@ -27,6 +27,7 @@ config NET_RADIO
 
 config NET_WIRELESS_RTNETLINK
        bool "Wireless Extension API over RtNetlink"
+       depends on NET_RADIO
        ---help---
          Support the Wireless Extension API over the RtNetlink socket
          in addition to the traditional ioctl interface (selected above).
index 761021603597036b041fe8f3ce9a1b8540249af6..8037e5806d0a48b33a28815cdd828cb90cfe77eb 100644 (file)
@@ -426,7 +426,7 @@ static void __devexit zorro8390_remove_one(struct zorro_dev *z)
 
 static int __init zorro8390_init_module(void)
 {
-    return zorro_module_init(&zorro8390_driver);
+    return zorro_register_driver(&zorro8390_driver);
 }
 
 static void __exit zorro8390_cleanup_module(void)
index 57fd60314d591516e1a7a7c81ff030ac552978a9..b1b4b683cbdd5ed06886343ee389032048e2d5ca 100644 (file)
@@ -646,8 +646,10 @@ static int __init isapnp_create_device(struct pnp_card *card,
                                size = 0;
                                skip = 0;
                                option = pnp_register_independent_option(dev);
-                               if (!option)
+                               if (!option) {
+                                       kfree(dev);
                                        return 1;
+                               }
                                pnp_add_card_device(card,dev);
                        } else {
                                skip = 1;
index 0eab05a37e6555a7d3a4c444b71fd7a78c468281..0a9f12c4e91154b57d73dd39e58ade8a6663c34e 100644 (file)
@@ -43,7 +43,6 @@ MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
                   " Copyright 2000 IBM Corporation");
 MODULE_SUPPORTED_DEVICE("dasd");
-MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s");
 MODULE_LICENSE("GPL");
 
 /*
index f576f243cd936a77265371ca0d86b4931a595d72..2f720108a7e07da24632a68fe3d6ac88a0773139 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/config.h>
 #include <linux/ctype.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 #include <asm/debug.h>
 #include <asm/uaccess.h>
@@ -69,6 +70,8 @@ int dasd_autodetect = 0;      /* is true, when autodetection is active */
  * strings when running as a module.
  */
 static char *dasd[256];
+module_param_array(dasd, charp, NULL, 0);
+
 /*
  * Single spinlock to protect devmap structures and lists.
  */
index 583d2d8c8335eba6b6924786984836c30d89e3df..fad2109268bb3175321afd6c5b10f5e8d9e44ebb 100644 (file)
@@ -550,6 +550,6 @@ module_exit(cumanascsi2_exit);
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("Cumana SCSI-2 driver for Acorn machines");
-MODULE_PARM(term, "1-8i");
+module_param_array(term, int, NULL, 0);
 MODULE_PARM_DESC(term, "SCSI bus termination");
 MODULE_LICENSE("GPL");
index 3ffec7efc9d526b45413bbdeeab277fbc4277f58..dcbb4b2b3fe054ca4b70968b870c295c56ccfe17 100644 (file)
@@ -674,6 +674,6 @@ module_exit(eesox_exit);
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
-MODULE_PARM(term, "1-8i");
+module_param_array(term, int, NULL, 0);
 MODULE_PARM_DESC(term, "SCSI bus termination");
 MODULE_LICENSE("GPL");
index 3113bdcedb1334dbbb54aff3bc78ac9ab3cd81ae..3d69f6c45a6b5b80698bef6bedd3fbf14468db27 100644 (file)
@@ -466,6 +466,6 @@ module_exit(powertecscsi_exit);
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("Powertec SCSI driver");
-MODULE_PARM(term, "1-8i");
+module_param_array(term, int, NULL, 0);
 MODULE_PARM_DESC(term, "SCSI bus termination");
 MODULE_LICENSE("GPL");
index f4c1ca7c1572536452bd059e56d514b2a0180f2d..f677c5a32a681c505b8322263f4e3c987acdd00d 100644 (file)
@@ -239,17 +239,17 @@ static int atari_read_overruns = 0;
 #endif
 
 static int setup_can_queue = -1;
-MODULE_PARM(setup_can_queue, "i");
+module_param(setup_can_queue, int, 0);
 static int setup_cmd_per_lun = -1;
-MODULE_PARM(setup_cmd_per_lun, "i");
+module_param(setup_cmd_per_lun, int, 0);
 static int setup_sg_tablesize = -1;
-MODULE_PARM(setup_sg_tablesize, "i");
+module_param(setup_sg_tablesize, int, 0);
 #ifdef SUPPORT_TAGS
 static int setup_use_tagged_queuing = -1;
-MODULE_PARM(setup_use_tagged_queuing, "i");
+module_param(setup_use_tagged_queuing, int, 0);
 #endif
 static int setup_hostid = -1;
-MODULE_PARM(setup_hostid, "i");
+module_param(setup_hostid, int, 0);
 
 
 #if defined(CONFIG_TT_DMA_EMUL)
index 024ef86c52425cd9b3f5ed05b380dad3b0eff2c0..c647d85d97d14555fc93f02d28ed98d580ff3be3 100644 (file)
@@ -190,7 +190,7 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
        if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
                            SD_MAX_RETRIES, &data, NULL))
                return -EINVAL;
-       len = min(sizeof(buffer), data.length - data.header_length -
+       len = min_t(size_t, sizeof(buffer), data.length - data.header_length -
                  data.block_descriptor_length);
        buffer_data = buffer + data.header_length +
                data.block_descriptor_length;
index 4315afe9c080a6beb1103643e6f3509a28f31cd2..53e81a44c1a3917fece986bef143e38401ff6f7e 100644 (file)
@@ -55,6 +55,8 @@ static struct dio_driver hpdca_driver = {
 
 #endif
 
+static unsigned int num_ports;
+
 extern int hp300_uart_scode;
 
 /* Offset to UART registers from base of DCA */
@@ -199,6 +201,8 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
        out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
        udelay(100);
 
+       num_ports++;
+
        return 0;
 }
 #endif
@@ -206,7 +210,6 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
 static int __init hp300_8250_init(void)
 {
        static int called = 0;
-       int num_ports;
 #ifdef CONFIG_HPAPCI
        int line;
        unsigned long base;
@@ -221,11 +224,8 @@ static int __init hp300_8250_init(void)
        if (!MACH_IS_HP300)
                return -ENODEV;
 
-       num_ports = 0;
-
 #ifdef CONFIG_HPDCA
-       if (dio_module_init(&hpdca_driver) == 0)
-               num_ports++;
+       dio_register_driver(&hpdca_driver);
 #endif
 #ifdef CONFIG_HPAPCI
        if (hp300_model < HP_400) {
index a37579ce6d763c89223787ba01b782633038397d..c620209d7b9a5d70e31e933dd998026d0196a677 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2003-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -323,9 +323,12 @@ static unsigned int Num_of_ioc4_cards;
 #define IOC4_FIFO_CHARS        255
 
 /* Device name we're using */
-#define DEVICE_NAME    "ttyIOC"
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 50
+#define DEVICE_NAME_RS232  "ttyIOC"
+#define DEVICE_NAME_RS422  "ttyAIOC"
+#define DEVICE_MAJOR      204
+#define DEVICE_MINOR_RS232 50
+#define DEVICE_MINOR_RS422 84
+
 
 /* register offsets */
 #define IOC4_SERIAL_OFFSET     0x300
@@ -341,10 +344,8 @@ static unsigned int Num_of_ioc4_cards;
 #define MAX_BAUD_SUPPORTED     115200
 
 /* protocol types supported */
-enum sio_proto {
-       PROTO_RS232,
-       PROTO_RS422
-};
+#define PROTO_RS232    3
+#define PROTO_RS422    7
 
 /* Notification types */
 #define N_DATA_READY   0x01
@@ -395,11 +396,17 @@ enum sio_proto {
 /*
  * This is the entry saved by the driver - one per card
  */
+
+#define UART_PORT_MIN          0
+#define UART_PORT_RS232                UART_PORT_MIN
+#define UART_PORT_RS422                1
+#define UART_PORT_COUNT                2       /* one for each mode */
+
 struct ioc4_control {
        int ic_irq;
        struct {
-               /* uart ports are allocated here */
-               struct uart_port icp_uart_port;
+               /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
+               struct uart_port icp_uart_port[UART_PORT_COUNT];
                /* Handy reference material */
                struct ioc4_port *icp_port;
        } ic_port[IOC4_NUM_SERIAL_PORTS];
@@ -443,7 +450,9 @@ struct ioc4_soft {
 
 /* Local port info for each IOC4 serial ports */
 struct ioc4_port {
-       struct uart_port *ip_port;
+       struct uart_port *ip_port;      /* current active port ptr */
+       /* Ptrs for all ports */
+       struct uart_port *ip_all_ports[UART_PORT_COUNT];
        /* Back ptrs for this port */
        struct ioc4_control *ip_control;
        struct pci_dev *ip_pdev;
@@ -502,6 +511,9 @@ struct ioc4_port {
 #define DCD_ON         0x02
 #define LOWAT_WRITTEN  0x04
 #define READ_ABORTED   0x08
+#define PORT_ACTIVE    0x10
+#define PORT_INACTIVE  0       /* This is the value when "off" */
+
 
 /* Since each port has different register offsets and bitmasks
  * for everything, we'll store those that we need in tables so we
@@ -623,6 +635,23 @@ struct ring_buffer {
 static void receive_chars(struct uart_port *);
 static void handle_intr(void *arg, uint32_t sio_ir);
 
+/*
+ * port_is_active - determines if this port is currently active
+ * @port: ptr to soft struct for this port
+ * @uart_port: uart port to test for
+ */
+static inline int port_is_active(struct ioc4_port *port,
+               struct uart_port *uart_port)
+{
+       if (port) {
+               if ((port->ip_flags & PORT_ACTIVE)
+                                       && (port->ip_port == uart_port))
+                       return 1;
+       }
+       return 0;
+}
+
+
 /**
  * write_ireg - write the interrupt regs
  * @ioc4_soft: ptr to soft struct for this port
@@ -708,19 +737,33 @@ static int set_baud(struct ioc4_port *port, int baud)
 /**
  * get_ioc4_port - given a uart port, return the control structure
  * @port: uart port
+ * @set: set this port as current
  */
-static struct ioc4_port *get_ioc4_port(struct uart_port *the_port)
+static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
 {
        struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
        struct ioc4_control *control = idd->idd_serial_data;
-       int ii;
+       struct ioc4_port *port;
+       int port_num, port_type;
 
        if (control) {
-               for ( ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++ ) {
-                       if (!control->ic_port[ii].icp_port)
+               for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
+                                                       port_num++ ) {
+                       port = control->ic_port[port_num].icp_port;
+                       if (!port)
                                continue;
-                       if (the_port == control->ic_port[ii].icp_port->ip_port)
-                               return control->ic_port[ii].icp_port;
+                       for (port_type = UART_PORT_MIN;
+                                               port_type < UART_PORT_COUNT;
+                                               port_type++) {
+                               if (the_port == port->ip_all_ports
+                                                       [port_type]) {
+                                       /* set local copy */
+                                       if (set) {
+                                               port->ip_port = the_port;
+                                       }
+                                       return port;
+                               }
+                       }
                }
        }
        return NULL;
@@ -946,6 +989,7 @@ intr_connect(struct ioc4_soft *soft, int type,
  * @arg: handler arg
  * @regs: registers
  */
+
 static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
 {
        struct ioc4_soft *soft;
@@ -953,7 +997,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
        int xx, num_intrs = 0;
        int intr_type;
        int handled = 0;
-       struct ioc4_intr_info *ii;
+       struct ioc4_intr_info *intr_info;
 
        soft = arg;
        for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
@@ -966,13 +1010,13 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
                 * which interrupt bits are set.
                 */
                for (xx = 0; xx < num_intrs; xx++) {
-                       ii = &soft->is_intr_type[intr_type].is_intr_info[xx];
-                       if ((this_mir = this_ir & ii->sd_bits)) {
+                       intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
+                       if ((this_mir = this_ir & intr_info->sd_bits)) {
                                /* Disable owned interrupts, call handler */
                                handled++;
-                               write_ireg(soft, ii->sd_bits, IOC4_W_IEC,
+                               write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
                                                                intr_type);
-                               ii->sd_intr(ii->sd_info, this_mir);
+                               intr_info->sd_intr(intr_info->sd_info, this_mir);
                                this_ir &= ~this_mir;
                        }
                }
@@ -980,7 +1024,6 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
 #ifdef DEBUG_INTERRUPTS
        {
                struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
-               spinlock_t *lp = &soft->is_ir_lock;
                unsigned long flag;
 
                spin_lock_irqsave(&soft->is_ir_lock, flag);
@@ -1177,7 +1220,7 @@ static inline int local_open(struct ioc4_port *port)
 {
        int spiniter = 0;
 
-       port->ip_flags = 0;
+       port->ip_flags = PORT_ACTIVE;
 
        /* Pause the DMA interface if necessary */
        if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
@@ -1187,6 +1230,7 @@ static inline int local_open(struct ioc4_port *port)
                                & IOC4_SSCR_PAUSE_STATE) == 0) {
                        spiniter++;
                        if (spiniter > MAXITER) {
+                               port->ip_flags = PORT_INACTIVE;
                                return -1;
                        }
                }
@@ -1506,14 +1550,13 @@ static int set_notification(struct ioc4_port *port, int mask, int set_on)
 /**
  * set_mcr - set the master control reg
  * @the_port: port to use
- * @set: set ?
  * @mask1: mcr mask
  * @mask2: shadow mask
  */
-static inline int set_mcr(struct uart_port *the_port, int set,
+static inline int set_mcr(struct uart_port *the_port,
                int mask1, int mask2)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        uint32_t shadow;
        int spiniter = 0;
        char mcr;
@@ -1536,13 +1579,9 @@ static inline int set_mcr(struct uart_port *the_port, int set,
        mcr = (shadow & 0xff000000) >> 24;
 
        /* Set new value */
-       if (set) {
-               mcr |= mask1;
-               shadow |= mask2;
-       } else {
-               mcr &= ~mask1;
-               shadow &= ~mask2;
-       }
+       mcr |= mask1;
+       shadow |= mask2;
+
        writeb(mcr, &port->ip_uart_regs->i4u_mcr);
        writel(shadow, &port->ip_serial_regs->shadow);
 
@@ -1558,7 +1597,7 @@ static inline int set_mcr(struct uart_port *the_port, int set,
  * @port: port to use
  * @proto: protocol to use
  */
-static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto)
+static int ioc4_set_proto(struct ioc4_port *port, int proto)
 {
        struct hooks *hooks = port->ip_hooks;
 
@@ -1589,7 +1628,7 @@ static void transmit_chars(struct uart_port *the_port)
        int result;
        char *start;
        struct tty_struct *tty;
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        struct uart_info *info;
 
        if (!the_port)
@@ -1645,7 +1684,7 @@ static void
 ioc4_change_speed(struct uart_port *the_port,
                  struct termios *new_termios, struct termios *old_termios)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        int baud, bits;
        unsigned cflag;
        int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
@@ -1752,7 +1791,7 @@ static inline int ic4_startup_local(struct uart_port *the_port)
        if (!the_port)
                return -1;
 
-       port = get_ioc4_port(the_port);
+       port = get_ioc4_port(the_port, 0);
        if (!port)
                return -1;
 
@@ -1760,6 +1799,9 @@ static inline int ic4_startup_local(struct uart_port *the_port)
 
        local_open(port);
 
+       /* set the protocol - mapbase has the port type */
+       ioc4_set_proto(port, the_port->mapbase);
+
        /* set the speed of the serial port */
        ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0);
 
@@ -1768,17 +1810,17 @@ static inline int ic4_startup_local(struct uart_port *the_port)
 
 /*
  * ioc4_cb_output_lowat - called when the output low water mark is hit
- * @port: port to output
+ * @the_port: port to output
  */
-static void ioc4_cb_output_lowat(struct ioc4_port *port)
+static void ioc4_cb_output_lowat(struct uart_port *the_port)
 {
        unsigned long pflags;
 
        /* ip_lock is set on the call here */
-       if (port->ip_port) {
-               spin_lock_irqsave(&port->ip_port->lock, pflags);
-               transmit_chars(port->ip_port);
-               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
+       if (the_port) {
+               spin_lock_irqsave(&the_port->lock, pflags);
+               transmit_chars(the_port);
+               spin_unlock_irqrestore(&the_port->lock, pflags);
        }
 }
 
@@ -1923,7 +1965,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
                                        &port->ip_mem->sio_ir.raw);
 
                        if (port->ip_notify & N_OUTPUT_LOWAT)
-                               ioc4_cb_output_lowat(port);
+                               ioc4_cb_output_lowat(port->ip_port);
                }
 
                /* Handle tx_mt.  Must come after tx_explicit.  */
@@ -1936,7 +1978,7 @@ static void handle_intr(void *arg, uint32_t sio_ir)
                         * So send the notification now.
                         */
                        if (port->ip_notify & N_OUTPUT_LOWAT) {
-                               ioc4_cb_output_lowat(port);
+                               ioc4_cb_output_lowat(port->ip_port);
 
                                /* We need to reload the sio_ir since the lowat
                                 * call may have caused another write to occur,
@@ -2023,7 +2065,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
                                int len)
 {
        int prod_ptr, cons_ptr, total;
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        struct ring *inring;
        struct ring_entry *entry;
        struct hooks *hooks = port->ip_hooks;
@@ -2335,17 +2377,27 @@ static void receive_chars(struct uart_port *the_port)
  */
 static const char *ic4_type(struct uart_port *the_port)
 {
-       return "SGI IOC4 Serial";
+       if (the_port->mapbase == PROTO_RS232)
+               return "SGI IOC4 Serial [rs232]";
+       else
+               return "SGI IOC4 Serial [rs422]";
 }
 
 /**
- * ic4_tx_empty - Is the transmitter empty?  We pretend we're always empty
- * @port: Port to operate on (we ignore since we always return 1)
+ * ic4_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
  *
  */
 static unsigned int ic4_tx_empty(struct uart_port *the_port)
 {
-       return 1;
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+       unsigned int ret = 0;
+
+       if (port_is_active(port, the_port)) {
+               if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
+                       ret = TIOCSER_TEMT;
+       }
+       return ret;
 }
 
 /**
@@ -2355,6 +2407,10 @@ static unsigned int ic4_tx_empty(struct uart_port *the_port)
  */
 static void ic4_stop_tx(struct uart_port *the_port)
 {
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
+
+       if (port_is_active(port, the_port))
+               set_notification(port, N_OUTPUT_LOWAT, 0);
 }
 
 /**
@@ -2377,11 +2433,12 @@ static void ic4_shutdown(struct uart_port *the_port)
        struct ioc4_port *port;
        struct uart_info *info;
 
-       port = get_ioc4_port(the_port);
+       port = get_ioc4_port(the_port, 0);
        if (!port)
                return;
 
        info = the_port->info;
+       port->ip_port = NULL;
 
        wake_up_interruptible(&info->delta_msr_wait);
 
@@ -2390,6 +2447,7 @@ static void ic4_shutdown(struct uart_port *the_port)
 
        spin_lock_irqsave(&the_port->lock, port_flags);
        set_notification(port, N_ALL, 0);
+       port->ip_flags = PORT_INACTIVE;
        spin_unlock_irqrestore(&the_port->lock, port_flags);
 }
 
@@ -2402,6 +2460,11 @@ static void ic4_shutdown(struct uart_port *the_port)
 static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
 {
        unsigned char mcr = 0;
+       struct ioc4_port *port;
+
+       port = get_ioc4_port(the_port, 0);
+       if (!port_is_active(port, the_port))
+               return;
 
        if (mctrl & TIOCM_RTS)
                mcr |= UART_MCR_RTS;
@@ -2414,7 +2477,7 @@ static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
        if (mctrl & TIOCM_LOOP)
                mcr |= UART_MCR_LOOP;
 
-       set_mcr(the_port, 1, mcr, IOC4_SHADOW_DTR);
+       set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
 }
 
 /**
@@ -2424,11 +2487,11 @@ static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
  */
 static unsigned int ic4_get_mctrl(struct uart_port *the_port)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
        uint32_t shadow;
        unsigned int ret = 0;
 
-       if (!port)
+       if (!port_is_active(port, the_port))
                return 0;
 
        shadow = readl(&port->ip_serial_regs->shadow);
@@ -2448,9 +2511,9 @@ static unsigned int ic4_get_mctrl(struct uart_port *the_port)
  */
 static void ic4_start_tx(struct uart_port *the_port)
 {
-       struct ioc4_port *port = get_ioc4_port(the_port);
+       struct ioc4_port *port = get_ioc4_port(the_port, 0);
 
-       if (port) {
+       if (port_is_active(port, the_port)) {
                set_notification(port, N_OUTPUT_LOWAT, 1);
                enable_intrs(port, port->ip_hooks->intr_tx_mt);
        }
@@ -2467,7 +2530,7 @@ static void ic4_break_ctl(struct uart_port *the_port, int break_state)
 }
 
 /**
- * ic4_startup - Start up the serial port - always return 0 (We're always on)
+ * ic4_startup - Start up the serial port
  * @port: Port to operate on
  *
  */
@@ -2479,17 +2542,16 @@ static int ic4_startup(struct uart_port *the_port)
        struct uart_info *info;
        unsigned long port_flags;
 
-       if (!the_port) {
+       if (!the_port)
                return -ENODEV;
-       }
-       port = get_ioc4_port(the_port);
-       if (!port) {
+       port = get_ioc4_port(the_port, 1);
+       if (!port)
                return -ENODEV;
-       }
        info = the_port->info;
 
        control = port->ip_control;
        if (!control) {
+               port->ip_port = NULL;
                return -ENODEV;
        }
 
@@ -2551,28 +2613,104 @@ static struct uart_ops ioc4_ops = {
  * Boot-time initialization code
  */
 
-static struct uart_driver ioc4_uart = {
+static struct uart_driver ioc4_uart_rs232 = {
        .owner          = THIS_MODULE,
-       .driver_name    = "ioc4_serial",
-       .dev_name       = DEVICE_NAME,
+       .driver_name    = "ioc4_serial_rs232",
+       .dev_name       = DEVICE_NAME_RS232,
        .major          = DEVICE_MAJOR,
-       .minor          = DEVICE_MINOR,
+       .minor          = DEVICE_MINOR_RS232,
        .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
 };
 
+static struct uart_driver ioc4_uart_rs422 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "ioc4_serial_rs422",
+       .dev_name       = DEVICE_NAME_RS422,
+       .major          = DEVICE_MAJOR,
+       .minor          = DEVICE_MINOR_RS422,
+       .nr             = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
+};
+
+
 /**
- * ioc4_serial_core_attach - register with serial core
+ * ioc4_serial_remove_one - detach function
+ *
+ * @idd: IOC4 master module data for this IOC4
+ */
+
+static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
+{
+       int port_num, port_type;
+       struct ioc4_control *control;
+       struct uart_port *the_port;
+       struct ioc4_port *port;
+       struct ioc4_soft *soft;
+
+       control = idd->idd_serial_data;
+
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               for (port_type = UART_PORT_MIN;
+                                       port_type < UART_PORT_COUNT;
+                                       port_type++) {
+                       the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type];
+                       if (the_port) {
+                               switch (port_type) {
+                               case UART_PORT_RS422:
+                                       uart_remove_one_port(&ioc4_uart_rs422,
+                                                       the_port);
+                                       break;
+                               default:
+                               case UART_PORT_RS232:
+                                       uart_remove_one_port(&ioc4_uart_rs232,
+                                                       the_port);
+                                       break;
+                               }
+                       }
+               }
+               port = control->ic_port[port_num].icp_port;
+               /* we allocate in pairs */
+               if (!(port_num & 1) && port) {
+                       pci_free_consistent(port->ip_pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                       kfree(port);
+               }
+       }
+       soft = control->ic_soft;
+       if (soft) {
+               free_irq(control->ic_irq, soft);
+               if (soft->is_ioc4_serial_addr) {
+                       release_region((unsigned long)
+                            soft->is_ioc4_serial_addr,
+                               sizeof(struct ioc4_serial));
+               }
+               kfree(soft);
+       }
+       kfree(control);
+       idd->idd_serial_data = NULL;
+
+       return 0;
+}
+
+
+/**
+ * ioc4_serial_core_attach_rs232 - register with serial core
  *             This is done during pci probing
  * @pdev: handle for this card
  */
 static inline int
-ioc4_serial_core_attach(struct pci_dev *pdev)
+ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
 {
        struct ioc4_port *port;
        struct uart_port *the_port;
        struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
        struct ioc4_control *control = idd->idd_serial_data;
-       int ii;
+       int port_num;
+       int port_type_idx;
+       struct uart_driver *u_driver;
+
 
        DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
                        __FUNCTION__, pdev, (void *)control));
@@ -2580,28 +2718,36 @@ ioc4_serial_core_attach(struct pci_dev *pdev)
        if (!control)
                return -ENODEV;
 
+       port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
+                                               : UART_PORT_RS422;
+
+       u_driver = (port_type == PROTO_RS232)   ? &ioc4_uart_rs232
+                                               : &ioc4_uart_rs422;
+
        /* once around for each port on this card */
-       for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
-               the_port = &control->ic_port[ii].icp_uart_port;
-               port = control->ic_port[ii].icp_port;
-               port->ip_port = the_port;
+       for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
+               the_port = &control->ic_port[port_num].icp_uart_port
+                                                       [port_type_idx];
+               port = control->ic_port[port_num].icp_port;
+               port->ip_all_ports[port_type_idx] = the_port;
 
-               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p\n",
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
                                __FUNCTION__, (void *)the_port,
-                               (void *)port));
+                               (void *)port,
+                               port_type == PROTO_RS232 ? "rs232" : "rs422"));
 
                /* membase, iobase and mapbase just need to be non-0 */
                the_port->membase = (unsigned char __iomem *)1;
-               the_port->iobase = (pdev->bus->number << 16) |  ii;
-               the_port->line = (Num_of_ioc4_cards << 2) | ii;
-               the_port->mapbase = 1;
+               the_port->iobase = (pdev->bus->number << 16) |  port_num;
+               the_port->line = (Num_of_ioc4_cards << 2) | port_num;
+               the_port->mapbase = port_type;
                the_port->type = PORT_16550A;
                the_port->fifosize = IOC4_FIFO_CHARS;
                the_port->ops = &ioc4_ops;
                the_port->irq = control->ic_irq;
                the_port->dev = &pdev->dev;
                spin_lock_init(&the_port->lock);
-               if (uart_add_one_port(&ioc4_uart, the_port) < 0) {
+               if (uart_add_one_port(u_driver, the_port) < 0) {
                        printk(KERN_WARNING
                           "%s: unable to add port %d bus %d\n",
                               __FUNCTION__, the_port->line, pdev->bus->number);
@@ -2610,8 +2756,6 @@ ioc4_serial_core_attach(struct pci_dev *pdev)
                            ("IOC4 serial port %d irq = %d, bus %d\n",
                               the_port->line, the_port->irq, pdev->bus->number));
                }
-               /* all ports are rs232 for now */
-               ioc4_set_proto(port, PROTO_RS232);
        }
        return 0;
 }
@@ -2631,7 +2775,8 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
        int ret = 0;
 
 
-       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id));
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev,
+                                                       idd->idd_pci_id));
 
        /* request serial registers */
        tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
@@ -2653,11 +2798,11 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
                goto out2;
        }
        DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
-                               __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial));
+                               __FUNCTION__, (void *)idd->idd_misc_regs,
+                               (void *)serial));
 
        /* Get memory for the new card */
-       control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS,
-                                               GFP_KERNEL);
+       control = kmalloc(sizeof(struct ioc4_control), GFP_KERNEL);
 
        if (!control) {
                printk(KERN_WARNING "ioc4_attach_one"
@@ -2702,7 +2847,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
 
        /* Hook up interrupt handler */
        if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ,
-                               "sgi-ioc4serial", (void *)soft)) {
+                               "sgi-ioc4serial", soft)) {
                control->ic_irq = idd->idd_pdev->irq;
        } else {
                printk(KERN_WARNING
@@ -2713,16 +2858,21 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
        if (ret)
                goto out4;
 
-       /* register port with the serial core */
+       /* register port with the serial core - 1 rs232, 1 rs422 */
 
-       if ((ret = ioc4_serial_core_attach(idd->idd_pdev)))
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
                goto out4;
 
+       if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
+               goto out5;
+
        Num_of_ioc4_cards++;
 
        return ret;
 
        /* error exits that give back resources */
+out5:
+       ioc4_serial_remove_one(idd);
 out4:
        kfree(soft);
 out3:
@@ -2735,52 +2885,6 @@ out1:
 }
 
 
-/**
- * ioc4_serial_remove_one - detach function
- *
- * @idd: IOC4 master module data for this IOC4
- */
-
-int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
-{
-       int ii;
-       struct ioc4_control *control;
-       struct uart_port *the_port;
-       struct ioc4_port *port;
-       struct ioc4_soft *soft;
-
-       control = idd->idd_serial_data;
-
-       for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) {
-               the_port = &control->ic_port[ii].icp_uart_port;
-               if (the_port) {
-                       uart_remove_one_port(&ioc4_uart, the_port);
-               }
-               port = control->ic_port[ii].icp_port;
-               if (!(ii & 1) && port) {
-                       pci_free_consistent(port->ip_pdev,
-                                       TOTAL_RING_BUF_SIZE,
-                                       (void *)port->ip_cpu_ringbuf,
-                                       port->ip_dma_ringbuf);
-                       kfree(port);
-               }
-       }
-       soft = control->ic_soft;
-       if (soft) {
-               free_irq(control->ic_irq, (void *)soft);
-               if (soft->is_ioc4_serial_addr) {
-                       release_region((unsigned long)
-                            soft->is_ioc4_serial_addr,
-                               sizeof(struct ioc4_serial));
-               }
-               kfree(soft);
-       }
-       kfree(control);
-       idd->idd_serial_data = NULL;
-
-       return 0;
-}
-
 static struct ioc4_submodule ioc4_serial_submodule = {
        .is_name = "IOC4_serial",
        .is_owner = THIS_MODULE,
@@ -2796,9 +2900,15 @@ int ioc4_serial_init(void)
        int ret;
 
        /* register with serial core */
-       if ((ret = uart_register_driver(&ioc4_uart)) < 0) {
+       if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
+               printk(KERN_WARNING
+                       "%s: Couldn't register rs232 IOC4 serial driver\n",
+                       __FUNCTION__);
+               return ret;
+       }
+       if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
                printk(KERN_WARNING
-                       "%s: Couldn't register IOC4 serial driver\n",
+                       "%s: Couldn't register rs422 IOC4 serial driver\n",
                        __FUNCTION__);
                return ret;
        }
@@ -2810,7 +2920,8 @@ int ioc4_serial_init(void)
 static void __devexit ioc4_serial_exit(void)
 {
        ioc4_unregister_submodule(&ioc4_serial_submodule);
-       uart_unregister_driver(&ioc4_uart);
+       uart_unregister_driver(&ioc4_uart_rs232);
+       uart_unregister_driver(&ioc4_uart_rs422);
 }
 
 module_init(ioc4_serial_init);
index 0ca83ac31d07a379eb95727ff8718392dd073c37..94681922ea0a6a2e874bef249520ce541a035ee4 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * drivers/serial/mpsc.c
- *
  * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240,
  * GT64260, MV64340, MV64360, GT96100, ... ).
  *
  * 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
  */
 
+#include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mv643xx.h>
 #include <linux/platform_device.h>
 
-#include "mpsc.h"
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#define        MPSC_NUM_CTLRS          2
+
+/*
+ * Descriptors and buffers must be cache line aligned.
+ * Buffers lengths must be multiple of cache line size.
+ * Number of Tx & Rx descriptors must be powers of 2.
+ */
+#define        MPSC_RXR_ENTRIES        32
+#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
+#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
+#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
+#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
+
+#define        MPSC_TXR_ENTRIES        32
+#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
+#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
+#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
+#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
+
+#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE +        \
+                               MPSC_TXR_SIZE + MPSC_TXB_SIZE +         \
+                               dma_get_cache_alignment() /* for alignment */)
+
+/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
+struct mpsc_rx_desc {
+       u16 bufsize;
+       u16 bytecnt;
+       u32 cmdstat;
+       u32 link;
+       u32 buf_ptr;
+} __attribute((packed));
+
+struct mpsc_tx_desc {
+       u16 bytecnt;
+       u16 shadow;
+       u32 cmdstat;
+       u32 link;
+       u32 buf_ptr;
+} __attribute((packed));
+
+/*
+ * Some regs that have the erratum that you can't read them are are shared
+ * between the two MPSC controllers.  This struct contains those shared regs.
+ */
+struct mpsc_shared_regs {
+       phys_addr_t mpsc_routing_base_p;
+       phys_addr_t sdma_intr_base_p;
+
+       void __iomem *mpsc_routing_base;
+       void __iomem *sdma_intr_base;
+
+       u32 MPSC_MRR_m;
+       u32 MPSC_RCRR_m;
+       u32 MPSC_TCRR_m;
+       u32 SDMA_INTR_CAUSE_m;
+       u32 SDMA_INTR_MASK_m;
+};
+
+/* The main driver data structure */
+struct mpsc_port_info {
+       struct uart_port port;  /* Overlay uart_port structure */
+
+       /* Internal driver state for this ctlr */
+       u8 ready;
+       u8 rcv_data;
+       tcflag_t c_iflag;       /* save termios->c_iflag */
+       tcflag_t c_cflag;       /* save termios->c_cflag */
+
+       /* Info passed in from platform */
+       u8 mirror_regs;         /* Need to mirror regs? */
+       u8 cache_mgmt;          /* Need manual cache mgmt? */
+       u8 brg_can_tune;        /* BRG has baud tuning? */
+       u32 brg_clk_src;
+       u16 mpsc_max_idle;
+       int default_baud;
+       int default_bits;
+       int default_parity;
+       int default_flow;
+
+       /* Physical addresses of various blocks of registers (from platform) */
+       phys_addr_t mpsc_base_p;
+       phys_addr_t sdma_base_p;
+       phys_addr_t brg_base_p;
+
+       /* Virtual addresses of various blocks of registers (from platform) */
+       void __iomem *mpsc_base;
+       void __iomem *sdma_base;
+       void __iomem *brg_base;
+
+       /* Descriptor ring and buffer allocations */
+       void *dma_region;
+       dma_addr_t dma_region_p;
+
+       dma_addr_t rxr;         /* Rx descriptor ring */
+       dma_addr_t rxr_p;       /* Phys addr of rxr */
+       u8 *rxb;                /* Rx Ring I/O buf */
+       u8 *rxb_p;              /* Phys addr of rxb */
+       u32 rxr_posn;           /* First desc w/ Rx data */
+
+       dma_addr_t txr;         /* Tx descriptor ring */
+       dma_addr_t txr_p;       /* Phys addr of txr */
+       u8 *txb;                /* Tx Ring I/O buf */
+       u8 *txb_p;              /* Phys addr of txb */
+       int txr_head;           /* Where new data goes */
+       int txr_tail;           /* Where sent data comes off */
+
+       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
+       u32 MPSC_MPCR_m;
+       u32 MPSC_CHR_1_m;
+       u32 MPSC_CHR_2_m;
+       u32 MPSC_CHR_10_m;
+       u32 BRG_BCR_m;
+       struct mpsc_shared_regs *shared_regs;
+};
+
+/* Hooks to platform-specific code */
+int mpsc_platform_register_driver(void);
+void mpsc_platform_unregister_driver(void);
+
+/* Hooks back in to mpsc common to be called by platform-specific code */
+struct mpsc_port_info *mpsc_device_probe(int index);
+struct mpsc_port_info *mpsc_device_remove(int index);
+
+/* Main MPSC Configuration Register Offsets */
+#define        MPSC_MMCRL                      0x0000
+#define        MPSC_MMCRH                      0x0004
+#define        MPSC_MPCR                       0x0008
+#define        MPSC_CHR_1                      0x000c
+#define        MPSC_CHR_2                      0x0010
+#define        MPSC_CHR_3                      0x0014
+#define        MPSC_CHR_4                      0x0018
+#define        MPSC_CHR_5                      0x001c
+#define        MPSC_CHR_6                      0x0020
+#define        MPSC_CHR_7                      0x0024
+#define        MPSC_CHR_8                      0x0028
+#define        MPSC_CHR_9                      0x002c
+#define        MPSC_CHR_10                     0x0030
+#define        MPSC_CHR_11                     0x0034
+
+#define        MPSC_MPCR_FRZ                   (1 << 9)
+#define        MPSC_MPCR_CL_5                  0
+#define        MPSC_MPCR_CL_6                  1
+#define        MPSC_MPCR_CL_7                  2
+#define        MPSC_MPCR_CL_8                  3
+#define        MPSC_MPCR_SBL_1                 0
+#define        MPSC_MPCR_SBL_2                 1
+
+#define        MPSC_CHR_2_TEV                  (1<<1)
+#define        MPSC_CHR_2_TA                   (1<<7)
+#define        MPSC_CHR_2_TTCS                 (1<<9)
+#define        MPSC_CHR_2_REV                  (1<<17)
+#define        MPSC_CHR_2_RA                   (1<<23)
+#define        MPSC_CHR_2_CRD                  (1<<25)
+#define        MPSC_CHR_2_EH                   (1<<31)
+#define        MPSC_CHR_2_PAR_ODD              0
+#define        MPSC_CHR_2_PAR_SPACE            1
+#define        MPSC_CHR_2_PAR_EVEN             2
+#define        MPSC_CHR_2_PAR_MARK             3
+
+/* MPSC Signal Routing */
+#define        MPSC_MRR                        0x0000
+#define        MPSC_RCRR                       0x0004
+#define        MPSC_TCRR                       0x0008
+
+/* Serial DMA Controller Interface Registers */
+#define        SDMA_SDC                        0x0000
+#define        SDMA_SDCM                       0x0008
+#define        SDMA_RX_DESC                    0x0800
+#define        SDMA_RX_BUF_PTR                 0x0808
+#define        SDMA_SCRDP                      0x0810
+#define        SDMA_TX_DESC                    0x0c00
+#define        SDMA_SCTDP                      0x0c10
+#define        SDMA_SFTDP                      0x0c14
+
+#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
+#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
+#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
+#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
+#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
+#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
+#define        SDMA_DESC_CMDSTAT_A             (1<<11)
+#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
+#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
+#define        SDMA_DESC_CMDSTAT_C             (1<<14)
+#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
+#define        SDMA_DESC_CMDSTAT_L             (1<<16)
+#define        SDMA_DESC_CMDSTAT_F             (1<<17)
+#define        SDMA_DESC_CMDSTAT_P             (1<<18)
+#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
+#define        SDMA_DESC_CMDSTAT_O             (1<<31)
+
+#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O |  \
+                                       SDMA_DESC_CMDSTAT_EI)
+
+#define        SDMA_SDC_RFT                    (1<<0)
+#define        SDMA_SDC_SFM                    (1<<1)
+#define        SDMA_SDC_BLMR                   (1<<6)
+#define        SDMA_SDC_BLMT                   (1<<7)
+#define        SDMA_SDC_POVR                   (1<<8)
+#define        SDMA_SDC_RIFB                   (1<<9)
+
+#define        SDMA_SDCM_ERD                   (1<<7)
+#define        SDMA_SDCM_AR                    (1<<15)
+#define        SDMA_SDCM_STD                   (1<<16)
+#define        SDMA_SDCM_TXD                   (1<<23)
+#define        SDMA_SDCM_AT                    (1<<31)
+
+#define        SDMA_0_CAUSE_RXBUF              (1<<0)
+#define        SDMA_0_CAUSE_RXERR              (1<<1)
+#define        SDMA_0_CAUSE_TXBUF              (1<<2)
+#define        SDMA_0_CAUSE_TXEND              (1<<3)
+#define        SDMA_1_CAUSE_RXBUF              (1<<8)
+#define        SDMA_1_CAUSE_RXERR              (1<<9)
+#define        SDMA_1_CAUSE_TXBUF              (1<<10)
+#define        SDMA_1_CAUSE_TXEND              (1<<11)
+
+#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR | \
+       SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
+#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND | \
+       SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
+
+/* SDMA Interrupt registers */
+#define        SDMA_INTR_CAUSE                 0x0000
+#define        SDMA_INTR_MASK                  0x0080
+
+/* Baud Rate Generator Interface Registers */
+#define        BRG_BCR                         0x0000
+#define        BRG_BTR                         0x0004
 
 /*
  * Define how this driver is known to the outside (we've been assigned a
@@ -1165,7 +1417,7 @@ mpsc_startup(struct uart_port *port)
                        flag = SA_SHIRQ;
 
                if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
-                               "mpsc/sdma", pi))
+                               "mpsc-sdma", pi))
                        printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
                               pi->port.irq);
 
diff --git a/drivers/serial/mpsc.h b/drivers/serial/mpsc.h
deleted file mode 100644 (file)
index 678dbcf..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * drivers/serial/mpsc.h
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2004 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef        __MPSC_H__
-#define        __MPSC_H__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/mv643xx.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#define        MPSC_NUM_CTLRS          2
-
-/*
- * Descriptors and buffers must be cache line aligned.
- * Buffers lengths must be multiple of cache line size.
- * Number of Tx & Rx descriptors must be powers of 2.
- */
-#define        MPSC_RXR_ENTRIES        32
-#define        MPSC_RXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXR_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE)
-#define        MPSC_RXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_RXB_SIZE           (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE)
-
-#define        MPSC_TXR_ENTRIES        32
-#define        MPSC_TXRE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXR_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE)
-#define        MPSC_TXBE_SIZE          dma_get_cache_alignment()
-#define        MPSC_TXB_SIZE           (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
-
-#define        MPSC_DMA_ALLOC_SIZE     (MPSC_RXR_SIZE + MPSC_RXB_SIZE +        \
-                               MPSC_TXR_SIZE + MPSC_TXB_SIZE +         \
-                               dma_get_cache_alignment() /* for alignment */)
-
-/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
-struct mpsc_rx_desc {
-       u16 bufsize;
-       u16 bytecnt;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-struct mpsc_tx_desc {
-       u16 bytecnt;
-       u16 shadow;
-       u32 cmdstat;
-       u32 link;
-       u32 buf_ptr;
-} __attribute((packed));
-
-/*
- * Some regs that have the erratum that you can't read them are are shared
- * between the two MPSC controllers.  This struct contains those shared regs.
- */
-struct mpsc_shared_regs {
-       phys_addr_t mpsc_routing_base_p;
-       phys_addr_t sdma_intr_base_p;
-
-       void __iomem *mpsc_routing_base;
-       void __iomem *sdma_intr_base;
-
-       u32 MPSC_MRR_m;
-       u32 MPSC_RCRR_m;
-       u32 MPSC_TCRR_m;
-       u32 SDMA_INTR_CAUSE_m;
-       u32 SDMA_INTR_MASK_m;
-};
-
-/* The main driver data structure */
-struct mpsc_port_info {
-       struct uart_port port;  /* Overlay uart_port structure */
-
-       /* Internal driver state for this ctlr */
-       u8 ready;
-       u8 rcv_data;
-       tcflag_t c_iflag;       /* save termios->c_iflag */
-       tcflag_t c_cflag;       /* save termios->c_cflag */
-
-       /* Info passed in from platform */
-       u8 mirror_regs;         /* Need to mirror regs? */
-       u8 cache_mgmt;          /* Need manual cache mgmt? */
-       u8 brg_can_tune;        /* BRG has baud tuning? */
-       u32 brg_clk_src;
-       u16 mpsc_max_idle;
-       int default_baud;
-       int default_bits;
-       int default_parity;
-       int default_flow;
-
-       /* Physical addresses of various blocks of registers (from platform) */
-       phys_addr_t mpsc_base_p;
-       phys_addr_t sdma_base_p;
-       phys_addr_t brg_base_p;
-
-       /* Virtual addresses of various blocks of registers (from platform) */
-       void __iomem *mpsc_base;
-       void __iomem *sdma_base;
-       void __iomem *brg_base;
-
-       /* Descriptor ring and buffer allocations */
-       void *dma_region;
-       dma_addr_t dma_region_p;
-
-       dma_addr_t rxr;         /* Rx descriptor ring */
-       dma_addr_t rxr_p;       /* Phys addr of rxr */
-       u8 *rxb;                /* Rx Ring I/O buf */
-       u8 *rxb_p;              /* Phys addr of rxb */
-       u32 rxr_posn;           /* First desc w/ Rx data */
-
-       dma_addr_t txr;         /* Tx descriptor ring */
-       dma_addr_t txr_p;       /* Phys addr of txr */
-       u8 *txb;                /* Tx Ring I/O buf */
-       u8 *txb_p;              /* Phys addr of txb */
-       int txr_head;           /* Where new data goes */
-       int txr_tail;           /* Where sent data comes off */
-
-       /* Mirrored values of regs we can't read (if 'mirror_regs' set) */
-       u32 MPSC_MPCR_m;
-       u32 MPSC_CHR_1_m;
-       u32 MPSC_CHR_2_m;
-       u32 MPSC_CHR_10_m;
-       u32 BRG_BCR_m;
-       struct mpsc_shared_regs *shared_regs;
-};
-
-/* Hooks to platform-specific code */
-int mpsc_platform_register_driver(void);
-void mpsc_platform_unregister_driver(void);
-
-/* Hooks back in to mpsc common to be called by platform-specific code */
-struct mpsc_port_info *mpsc_device_probe(int index);
-struct mpsc_port_info *mpsc_device_remove(int index);
-
-/*
- *****************************************************************************
- *
- *     Multi-Protocol Serial Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* Main Configuratino Register Offsets */
-#define        MPSC_MMCRL                      0x0000
-#define        MPSC_MMCRH                      0x0004
-#define        MPSC_MPCR                       0x0008
-#define        MPSC_CHR_1                      0x000c
-#define        MPSC_CHR_2                      0x0010
-#define        MPSC_CHR_3                      0x0014
-#define        MPSC_CHR_4                      0x0018
-#define        MPSC_CHR_5                      0x001c
-#define        MPSC_CHR_6                      0x0020
-#define        MPSC_CHR_7                      0x0024
-#define        MPSC_CHR_8                      0x0028
-#define        MPSC_CHR_9                      0x002c
-#define        MPSC_CHR_10                     0x0030
-#define        MPSC_CHR_11                     0x0034
-
-#define        MPSC_MPCR_FRZ                   (1 << 9)
-#define        MPSC_MPCR_CL_5                  0
-#define        MPSC_MPCR_CL_6                  1
-#define        MPSC_MPCR_CL_7                  2
-#define        MPSC_MPCR_CL_8                  3
-#define        MPSC_MPCR_SBL_1                 0
-#define        MPSC_MPCR_SBL_2                 1
-
-#define        MPSC_CHR_2_TEV                  (1<<1)
-#define        MPSC_CHR_2_TA                   (1<<7)
-#define        MPSC_CHR_2_TTCS                 (1<<9)
-#define        MPSC_CHR_2_REV                  (1<<17)
-#define        MPSC_CHR_2_RA                   (1<<23)
-#define        MPSC_CHR_2_CRD                  (1<<25)
-#define        MPSC_CHR_2_EH                   (1<<31)
-#define        MPSC_CHR_2_PAR_ODD              0
-#define        MPSC_CHR_2_PAR_SPACE            1
-#define        MPSC_CHR_2_PAR_EVEN             2
-#define        MPSC_CHR_2_PAR_MARK             3
-
-/* MPSC Signal Routing */
-#define        MPSC_MRR                        0x0000
-#define        MPSC_RCRR                       0x0004
-#define        MPSC_TCRR                       0x0008
-
-/*
- *****************************************************************************
- *
- *     Serial DMA Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define        SDMA_SDC                        0x0000
-#define        SDMA_SDCM                       0x0008
-#define        SDMA_RX_DESC                    0x0800
-#define        SDMA_RX_BUF_PTR                 0x0808
-#define        SDMA_SCRDP                      0x0810
-#define        SDMA_TX_DESC                    0x0c00
-#define        SDMA_SCTDP                      0x0c10
-#define        SDMA_SFTDP                      0x0c14
-
-#define        SDMA_DESC_CMDSTAT_PE            (1<<0)
-#define        SDMA_DESC_CMDSTAT_CDL           (1<<1)
-#define        SDMA_DESC_CMDSTAT_FR            (1<<3)
-#define        SDMA_DESC_CMDSTAT_OR            (1<<6)
-#define        SDMA_DESC_CMDSTAT_BR            (1<<9)
-#define        SDMA_DESC_CMDSTAT_MI            (1<<10)
-#define        SDMA_DESC_CMDSTAT_A             (1<<11)
-#define        SDMA_DESC_CMDSTAT_AM            (1<<12)
-#define        SDMA_DESC_CMDSTAT_CT            (1<<13)
-#define        SDMA_DESC_CMDSTAT_C             (1<<14)
-#define        SDMA_DESC_CMDSTAT_ES            (1<<15)
-#define        SDMA_DESC_CMDSTAT_L             (1<<16)
-#define        SDMA_DESC_CMDSTAT_F             (1<<17)
-#define        SDMA_DESC_CMDSTAT_P             (1<<18)
-#define        SDMA_DESC_CMDSTAT_EI            (1<<23)
-#define        SDMA_DESC_CMDSTAT_O             (1<<31)
-
-#define SDMA_DESC_DFLT                 (SDMA_DESC_CMDSTAT_O |  \
-                                       SDMA_DESC_CMDSTAT_EI)
-
-#define        SDMA_SDC_RFT                    (1<<0)
-#define        SDMA_SDC_SFM                    (1<<1)
-#define        SDMA_SDC_BLMR                   (1<<6)
-#define        SDMA_SDC_BLMT                   (1<<7)
-#define        SDMA_SDC_POVR                   (1<<8)
-#define        SDMA_SDC_RIFB                   (1<<9)
-
-#define        SDMA_SDCM_ERD                   (1<<7)
-#define        SDMA_SDCM_AR                    (1<<15)
-#define        SDMA_SDCM_STD                   (1<<16)
-#define        SDMA_SDCM_TXD                   (1<<23)
-#define        SDMA_SDCM_AT                    (1<<31)
-
-#define        SDMA_0_CAUSE_RXBUF              (1<<0)
-#define        SDMA_0_CAUSE_RXERR              (1<<1)
-#define        SDMA_0_CAUSE_TXBUF              (1<<2)
-#define        SDMA_0_CAUSE_TXEND              (1<<3)
-#define        SDMA_1_CAUSE_RXBUF              (1<<8)
-#define        SDMA_1_CAUSE_RXERR              (1<<9)
-#define        SDMA_1_CAUSE_TXBUF              (1<<10)
-#define        SDMA_1_CAUSE_TXEND              (1<<11)
-
-#define        SDMA_CAUSE_RX_MASK      (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR | \
-       SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define        SDMA_CAUSE_TX_MASK      (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND | \
-       SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
-
-/* SDMA Interrupt registers */
-#define        SDMA_INTR_CAUSE                 0x0000
-#define        SDMA_INTR_MASK                  0x0080
-
-/*
- *****************************************************************************
- *
- *     Baud Rate Generator Interface Registers
- *
- *****************************************************************************
- */
-
-#define        BRG_BCR                         0x0000
-#define        BRG_BTR                         0x0004
-
-#endif                         /* __MPSC_H__ */
index b1222cd4aa46b1388e455aef5690f9b8c2827c65..7fdbc5dad5fd9d364a62fa95793c93b8a73734cf 100644 (file)
@@ -87,8 +87,6 @@ source "drivers/usb/input/Kconfig"
 
 source "drivers/usb/image/Kconfig"
 
-source "drivers/usb/media/Kconfig"
-
 source "drivers/usb/net/Kconfig"
 
 source "drivers/usb/mon/Kconfig"
index bb36a1c1dbb312851327be304eced6856d13a112..9b7d9769fdcc7179d8e95786b11f0a6f27d40ab4 100644 (file)
@@ -35,20 +35,6 @@ obj-$(CONFIG_USB_WACOM)              += input/
 obj-$(CONFIG_USB_ACECAD)       += input/
 obj-$(CONFIG_USB_XPAD)         += input/
 
-obj-$(CONFIG_USB_DABUSB)       += media/
-obj-$(CONFIG_USB_DSBR)         += media/
-obj-$(CONFIG_USB_ET61X251)     += media/
-obj-$(CONFIG_USB_IBMCAM)       += media/
-obj-$(CONFIG_USB_KONICAWC)     += media/
-obj-$(CONFIG_USB_OV511)                += media/
-obj-$(CONFIG_USB_PWC)          += media/
-obj-$(CONFIG_USB_SE401)                += media/
-obj-$(CONFIG_USB_SN9C102)      += media/
-obj-$(CONFIG_USB_STV680)       += media/
-obj-$(CONFIG_USB_VICAM)                += media/
-obj-$(CONFIG_USB_W9968CF)      += media/
-obj-$(CONFIG_USB_ZC0301)       += media/
-
 obj-$(CONFIG_USB_CATC)         += net/
 obj-$(CONFIG_USB_KAWETH)       += net/
 obj-$(CONFIG_USB_PEGASUS)      += net/
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig
deleted file mode 100644 (file)
index 189d40f..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-#
-# USB Multimedia device configuration
-#
-comment "USB Multimedia devices"
-       depends on USB
-
-config USB_DABUSB
-       tristate "DABUSB driver"
-       depends on USB
-       ---help---
-         A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
-         brought to you by the DAB-Team
-         <http://wwwbode.cs.tum.edu/Par/arch/dab/>.  This driver can be taken
-         as an example for URB-based bulk, control, and isochronous
-         transactions. URB's are explained in
-         <file:Documentation/usb/URB.txt>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dabusb.
-
-comment "Video4Linux support is needed for USB Multimedia device support"
-       depends on USB && VIDEO_DEV=n
-
-config USB_VICAM
-       tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
-       depends on USB && VIDEO_DEV && EXPERIMENTAL
-       ---help---
-         Say Y here if you have 3com homeconnect camera (vicam).
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Multimedia Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vicam.
-
-config USB_DSBR
-       tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-       depends on USB && VIDEO_DEV && EXPERIMENTAL
-       ---help---
-         Say Y here if you want to connect this type of radio to your
-         computer's USB port. Note that the audio is not digital, and
-         you must connect the line out connector to a sound card or a
-         set of speakers.
-
-         This driver uses the Video For Linux API.  You must enable
-         (Y or M in config) Video For Linux (under Character Devices)
-         to use this driver.  Information on this API and pointers to
-         "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dsbr100.
-
-config USB_ET61X251
-       tristate "USB ET61X[12]51 PC Camera Controller support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for cameras based on Etoms ET61X151
-         or ET61X251 PC Camera Controllers.
-
-         See <file:Documentation/usb/et61x251.txt> for more informations.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called et61x251.
-
-config USB_IBMCAM
-       tristate "USB IBM (Xirlink) C-it Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect a IBM "C-It" camera, also known as
-         "Xirlink PC Camera" to your computer's USB port.  For more
-         information, read <file:Documentation/usb/ibmcam.txt>.
-
-         This driver uses the Video For Linux API.  You must enable
-         (Y or M in config) Video For Linux (under Character Devices)
-         to use this driver.  Information on this API and pointers to
-         "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ibmcam.
-
-         This camera has several configuration options which
-         can be specified when you load the module. Read
-         <file:Documentation/usb/ibmcam.txt> to learn more.
-
-config USB_KONICAWC
-       tristate "USB Konica Webcam support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for webcams based on a Konica
-         chipset. This is known to work with the Intel YC76 webcam.
-
-         This driver uses the Video For Linux API.  You must enable
-         (Y or M in config) Video For Linux (under Character Devices)
-         to use this driver.  Information on this API and pointers to
-         "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called konicawc.
-
-config USB_OV511
-       tristate "USB OV511 Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. See <file:Documentation/usb/ov511.txt> for more
-         information and for a list of supported cameras.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Character Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ov511.
-
-config USB_SE401
-       tristate "USB SE401 Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. See <file:Documentation/usb/se401.txt> for more
-         information and for a list of supported cameras.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Multimedia Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called se401.
-
-config USB_SN9C102
-       tristate "USB SN9C10x PC Camera Controller support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for cameras based on SONiX SN9C101,
-         SN9C102 or SN9C103 PC Camera Controllers.
-
-         See <file:Documentation/usb/sn9c102.txt> for more informations.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called sn9c102.
-
-config USB_STV680
-       tristate "USB STV680 (Pencam) Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. This includes the Pencam line of cameras.
-         See <file:Documentation/usb/stv680.txt> for more information and for
-         a list of supported cameras.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Multimedia Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called stv680.
-
-config USB_W9968CF
-       tristate "USB W996[87]CF JPEG Dual Mode Camera support"
-       depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP
-       ---help---
-         Say Y here if you want support for cameras based on OV681 or
-         Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-       
-         This driver has an optional plugin, which is distributed as a
-         separate module only (released under GPL). It allows to use higher 
-         resolutions and framerates, but cannot be included in the official 
-         Linux kernel for performance purposes.
-
-         See <file:Documentation/usb/w9968cf.txt> for more informations.
-
-         This driver uses the Video For Linux and the I2C APIs. It needs the
-         OmniVision Camera Chip support as well. You must say Y or M to
-         "Video For Linux", "I2C Support" and "OmniVision Camera Chip 
-         support" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called w9968cf.
-
-config USB_ZC0301
-       tristate "USB ZC0301 Image Processor and Control Chip support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for cameras based on the ZC0301
-         Image Processor and Control Chip.
-
-         See <file:Documentation/usb/zc0301.txt> for more informations.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zc0301.
-
-config USB_PWC
-       tristate "USB Philips Cameras"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y or M here if you want to use one of these Philips & OEM
-          webcams:
-           * Philips PCA645, PCA646
-           * Philips PCVC675, PCVC680, PCVC690
-           * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
-          * Askey VC010
-          * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' 
-             and 'Orbit'/'Sphere'
-           * Samsung MPC-C10, MPC-C30
-          * Creative Webcam 5, Pro Ex
-          * SOTEC Afina Eye
-          * Visionite VCS-UC300, VCS-UM100
-          
-         The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
-         and never will be, but the 665 and 720/20 are supported by other 
-         drivers.
-
-         See <file:Documentation/usb/philips.txt> for more information and
-         installation instructions.
-
-         The built-in microphone is enabled by selecting USB Audio support.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Character Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called pwc.
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
deleted file mode 100644 (file)
index 50e89a3..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Makefile for USB Media drivers
-#
-
-sn9c102-objs   := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
-                  sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
-                  sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
-                  sn9c102_tas5130d1b.o
-et61x251-objs  := et61x251_core.o et61x251_tas5130d1b.o
-zc0301-objs    := zc0301_core.o zc0301_pas202bcb.o
-
-obj-$(CONFIG_USB_DABUSB)       += dabusb.o
-obj-$(CONFIG_USB_DSBR)         += dsbr100.o
-obj-$(CONFIG_USB_ET61X251)     += et61x251.o
-obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o usbvideo.o ultracam.o
-obj-$(CONFIG_USB_KONICAWC)     += konicawc.o usbvideo.o
-obj-$(CONFIG_USB_OV511)                += ov511.o
-obj-$(CONFIG_USB_SE401)                += se401.o
-obj-$(CONFIG_USB_SN9C102)      += sn9c102.o
-obj-$(CONFIG_USB_STV680)       += stv680.o
-obj-$(CONFIG_USB_VICAM)                += vicam.o usbvideo.o
-obj-$(CONFIG_USB_W9968CF)      += w9968cf.o
-obj-$(CONFIG_USB_ZC0301)       += zc0301.o
-obj-$(CONFIG_USB_PWC)           += pwc/
diff --git a/drivers/usb/media/dabfirmware.h b/drivers/usb/media/dabfirmware.h
deleted file mode 100644 (file)
index d14d803..0000000
+++ /dev/null
@@ -1,1408 +0,0 @@
-/*
- * dabdata.h - dab usb firmware and bitstream data
- */
-
-static INTEL_HEX_RECORD firmware[] = {
-
-{  2, 0x0000, 0, {0x21,0x57} },
-{  3, 0x0003, 0, {0x02,0x01,0x66} },
-{  3, 0x000b, 0, {0x02,0x01,0x66} },
-{  3, 0x0013, 0, {0x02,0x01,0x66} },
-{  3, 0x001b, 0, {0x02,0x01,0x66} },
-{  3, 0x0023, 0, {0x02,0x01,0x66} },
-{  3, 0x002b, 0, {0x02,0x01,0x66} },
-{  3, 0x0033, 0, {0x02,0x03,0x0f} },
-{  3, 0x003b, 0, {0x02,0x01,0x66} },
-{  3, 0x0043, 0, {0x02,0x01,0x00} },
-{  3, 0x004b, 0, {0x02,0x01,0x66} },
-{  3, 0x0053, 0, {0x02,0x01,0x66} },
-{  3, 0x005b, 0, {0x02,0x04,0xbd} },
-{  3, 0x0063, 0, {0x02,0x01,0x67} },
-{  3, 0x0100, 0, {0x02,0x0c,0x5a} },
-{  3, 0x0104, 0, {0x02,0x01,0xed} },
-{  3, 0x0108, 0, {0x02,0x02,0x51} },
-{  3, 0x010c, 0, {0x02,0x02,0x7c} },
-{  3, 0x0110, 0, {0x02,0x02,0xe4} },
-{  1, 0x0114, 0, {0x32} },
-{  1, 0x0118, 0, {0x32} },
-{  3, 0x011c, 0, {0x02,0x05,0xfd} },
-{  3, 0x0120, 0, {0x02,0x00,0x00} },
-{  3, 0x0124, 0, {0x02,0x00,0x00} },
-{  3, 0x0128, 0, {0x02,0x04,0x3c} },
-{  3, 0x012c, 0, {0x02,0x04,0x6a} },
-{  3, 0x0130, 0, {0x02,0x00,0x00} },
-{  3, 0x0134, 0, {0x02,0x00,0x00} },
-{  3, 0x0138, 0, {0x02,0x00,0x00} },
-{  3, 0x013c, 0, {0x02,0x00,0x00} },
-{  3, 0x0140, 0, {0x02,0x00,0x00} },
-{  3, 0x0144, 0, {0x02,0x00,0x00} },
-{  3, 0x0148, 0, {0x02,0x00,0x00} },
-{  3, 0x014c, 0, {0x02,0x00,0x00} },
-{  3, 0x0150, 0, {0x02,0x00,0x00} },
-{  3, 0x0154, 0, {0x02,0x00,0x00} },
-{ 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} },
-{  5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} },
-{  1, 0x0166, 0, {0x32} },
-{ 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} },
-{ 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} },
-{  3, 0x019f, 0, {0x55,0x7f,0xf0} },
-{ 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} },
-{  3, 0x01da, 0, {0xd0,0xd0,0x32} },
-{  8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} },
-{  7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} },
-{  1, 0x01ec, 0, {0x22} },
-{ 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} },
-{ 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} },
-{ 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} },
-{  9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} },
-{  4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} },
-{ 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} },
-{ 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} },
-{  2, 0x023c, 0, {0x01,0x0b} },
-{  2, 0x023e, 0, {0x80,0xe3} },
-{  2, 0x0240, 0, {0xd0,0x86} },
-{ 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} },
-{  1, 0x0250, 0, {0x32} },
-{ 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
-{  4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} },
-{ 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
-{ 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} },
-{  6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} },
-{  6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
-{ 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} },
-{ 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
-{  4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} },
-{ 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} },
-{  7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} },
-{  6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
-{ 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} },
-{  5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} },
-{ 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
-{ 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} },
-{ 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} },
-{  1, 0x0398, 0, {0xf0} },
-{  1, 0x0399, 0, {0x22} },
-{ 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
-{ 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} },
-{ 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} },
-{ 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} },
-{  1, 0x03ca, 0, {0x22} },
-{ 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} },
-{  9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} },
-{  2, 0x03de, 0, {0x03,0x72} },
-{  1, 0x03e0, 0, {0x22} },
-{ 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} },
-{  9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} },
-{  9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} },
-{  9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} },
-{  8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} },
-{  1, 0x0410, 0,{0x22} },
-{ 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
-{  4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} },
-{ 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} },
-{  7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} },
-{ 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
-{  7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} },
-{ 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} },
-{ 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} },
-{ 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} },
-{  1, 0x04ee, 0, {0x22} },
-{  7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} },
-{  1, 0x04f6, 0, {0x22} },
-{ 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} },
-{ 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} },
-{ 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} },
-{ 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} },
-{  2, 0x052c, 0, {0x7a,0x00} },
-{  7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} },
-{  2, 0x0535, 0, {0x7b,0x00} },
-{ 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} },
-{  7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} },
-{  9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} },
-{  4, 0x0552, 0, {0x70,0x47,0x75,0x71} },
-{  8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} },
-{  5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} },
-{  1, 0x0563, 0, {0x22} },
-{ 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
-{ 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} },
-{ 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} },
-{ 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} },
-{  5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} },
-{  3, 0x05a1, 0, {0x02,0x05,0xf9} },
-{  6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} },
-{ 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} },
-{ 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} },
-{  2, 0x05c6, 0, {0x80,0x31} },
-{ 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} },
-{ 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} },
-{ 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} },
-{  7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} },
-{  3, 0x05f9, 0, {0x75,0x38,0x01} },
-{  1, 0x05fc, 0, {0x22} },
-{ 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
-{ 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} },
-{ 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} },
-{ 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} },
-{ 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} },
-{ 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} },
-{ 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} },
-{ 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} },
-{  3, 0x06a2, 0, {0xbf,0x81,0x0a} },
-{ 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} },
-{  8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} },
-{  3, 0x06b7, 0, {0xba,0x01,0x0c} },
-{ 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
-{ 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} },
-{  8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} },
-{  3, 0x06d9, 0, {0xba,0x01,0x0d} },
-{ 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
-{ 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} },
-{  8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} },
-{  3, 0x06fc, 0, {0xba,0x01,0x0d} },
-{ 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} },
-{ 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} },
-{  5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} },
-{  1, 0x071d, 0, {0x22} },
-{ 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} },
-{ 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
-{  9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
-{  9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
-{  7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} },
-{  3, 0x074d, 0, {0xba,0xff,0x00} },
-{  2, 0x0750, 0, {0x50,0x0a} },
-{ 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
-{ 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} },
-{  8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} },
-{  1, 0x076e, 0, {0x22} },
-{ 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} },
-{ 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} },
-{ 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} },
-{  9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} },
-{  5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} },
-{  7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} },
-{ 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} },
-{  4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} },
-{  9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} },
-{  7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} },
-{ 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} },
-{ 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} },
-{ 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
-{ 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} },
-{ 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} },
-{ 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} },
-{ 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} },
-{ 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} },
-{ 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} },
-{ 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} },
-{ 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} },
-{ 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} },
-{ 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} },
-{  9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} },
-{ 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} },
-{  9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x089d, 0, {0x80,0xe0} },
-{ 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} },
-{ 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} },
-{ 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
-{ 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x08d0, 0, {0x80,0xd9} },
-{ 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} },
-{ 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} },
-{ 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} },
-{ 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} },
-{ 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} },
-{ 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} },
-{ 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} },
-{ 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} },
-{  3, 0x0937, 0, {0x02,0x0a,0x3f} },
-{ 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} },
-{ 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} },
-{ 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
-{ 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} },
-{ 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} },
-{  2, 0x097a, 0, {0x60,0x0c} },
-{ 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} },
-{ 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} },
-{ 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} },
-{  6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} },
-{  3, 0x09a7, 0, {0xba,0xa0,0x00} },
-{  2, 0x09aa, 0, {0x50,0x24} },
-{ 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} },
-{ 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} },
-{  9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
-{  5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} },
-{  6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} },
-{ 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} },
-{ 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} },
-{  6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} },
-{  5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} },
-{  4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} },
-{ 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} },
-{ 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
-{  3, 0x0a1a, 0, {0x05,0xd0,0x04} },
-{  5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} },
-{  4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} },
-{ 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} },
-{ 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
-{  3, 0x0a3c, 0, {0x05,0xd0,0x04} },
-{ 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} },
-{ 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} },
-{ 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} },
-{  8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} },
-{  8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} },
-{ 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} },
-{  5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} },
-{  5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} },
-{  5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} },
-{ 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} },
-{  1, 0x0a9f, 0, {0x00} },
-{  7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} },
-{ 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} },
-{ 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
-{  9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} },
-{  3, 0x0ac8, 0, {0x02,0x0b,0x36} },
-{  5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} },
-{  3, 0x0ad0, 0, {0xbb,0x64,0x00} },
-{  2, 0x0ad3, 0, {0x50,0x1c} },
-{ 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
-{ 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} },
-{  1, 0x0af0, 0, {0xdf} },
-{ 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} },
-{ 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} },
-{ 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} },
-{  9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} },
-{ 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
-{ 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} },
-{  3, 0x0b36, 0, {0xba,0x2a,0x3b} },
-{ 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
-{ 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} },
-{  2, 0x0b54, 0, {0x7b,0x00} },
-{  3, 0x0b56, 0, {0xbb,0x0a,0x00} },
-{  5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} },
-{ 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
-{  8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} },
-{  3, 0x0b74, 0, {0xba,0x2b,0x1a} },
-{  8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} },
-{ 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} },
-{  4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} },
-{  3, 0x0b91, 0, {0xba,0x10,0x1f} },
-{ 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} },
-{ 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
-{  3, 0x0bb0, 0, {0x02,0x0c,0x2d} },
-{  3, 0x0bb3, 0, {0xba,0x11,0x12} },
-{ 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} },
-{  4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} },
-{  3, 0x0bc8, 0, {0xba,0x12,0x12} },
-{ 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} },
-{  4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} },
-{  3, 0x0bdd, 0, {0xba,0x13,0x0b} },
-{ 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} },
-{  3, 0x0beb, 0, {0xba,0x14,0x11} },
-{ 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} },
-{  3, 0x0bfc, 0, {0x02,0x80,0x2e} },
-{  3, 0x0bff, 0, {0xba,0x15,0x1d} },
-{ 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} },
-{ 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} },
-{  3, 0x0c1c, 0, {0x02,0x80,0x0e} },
-{  3, 0x0c1f, 0, {0xba,0x16,0x0b} },
-{ 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} },
-{ 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} },
-{  1, 0x0c38, 0, {0x22} },
-{  7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} },
-{  7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} },
-{  6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} },
-{ 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} },
-{ 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
-{ 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} },
-{  6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} },
-{  3, 0x0c97, 0, {0x02,0x0d,0x38} },
-{  3, 0x0c9a, 0, {0xba,0x80,0x14} },
-{ 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} },
-{  6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} },
-{  5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} },
-{  3, 0x0cb6, 0, {0x02,0x0d,0x1d} },
-{  8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} },
-{  2, 0x0cc1, 0, {0x40,0x21} },
-{  6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} },
-{ 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
-{ 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} },
-{  3, 0x0ce4, 0, {0xbc,0x81,0x00} },
-{  2, 0x0ce7, 0, {0x40,0x21} },
-{  6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} },
-{ 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
-{ 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} },
-{  5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} },
-{ 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} },
-{  5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} },
-{  3, 0x0d22, 0, {0x02,0x0e,0xc5} },
-{ 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} },
-{  5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} },
-{  3, 0x0d38, 0, {0xbb,0x01,0x2d} },
-{  6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
-{  3, 0x0d41, 0, {0xba,0x02,0x11} },
-{ 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
-{  4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} },
-{  5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} },
-{  3, 0x0d5a, 0, {0x02,0x0e,0xcd} },
-{ 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} },
-{  3, 0x0d68, 0, {0xbb,0x03,0x1f} },
-{  6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
-{  5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} },
-{  3, 0x0d76, 0, {0x02,0x0e,0xcd} },
-{ 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
-{  4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} },
-{  3, 0x0d8a, 0, {0xbb,0x06,0x54} },
-{  5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} },
-{  3, 0x0d92, 0, {0x02,0x0e,0xc5} },
-{  8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} },
-{ 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
-{  9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
-{ 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} },
-{  3, 0x0dbc, 0, {0x02,0x0e,0xc5} },
-{ 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} },
-{  3, 0x0dc9, 0, {0x02,0x0e,0xc5} },
-{ 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
-{  9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
-{  6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} },
-{  3, 0x0de7, 0, {0xbb,0x08,0x10} },
-{ 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
-{  3, 0x0df7, 0, {0x02,0x0e,0xcd} },
-{  3, 0x0dfa, 0, {0xbb,0x09,0x31} },
-{  5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} },
-{  3, 0x0e02, 0, {0x02,0x0e,0xc5} },
-{ 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} },
-{  8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} },
-{ 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} },
-{  9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} },
-{  3, 0x0e2e, 0, {0xbb,0x0a,0x27} },
-{  5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} },
-{  3, 0x0e36, 0, {0x02,0x0e,0xc5} },
-{ 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} },
-{ 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
-{  3, 0x0e55, 0, {0x02,0x0e,0xcd} },
-{  5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} },
-{  3, 0x0e5d, 0, {0x02,0x0e,0xa9} },
-{ 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} },
-{  8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} },
-{ 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} },
-{  4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} },
-{  8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} },
-{  8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} },
-{ 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} },
-{  5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} },
-{  5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} },
-{  5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} },
-{  5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} },
-{  5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} },
-{  3, 0x0ebd, 0, {0xbb,0x84,0x05} },
-{  5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} },
-{  8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} },
-{  6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} },
-{  2, 0x0ed3, 0, {0xd0,0x86} },
-{ 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} },
-{  7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} },
-{ 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} },
-{  9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} },
-{  7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} },
-{  7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} },
-{ 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} },
-{  7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} },
-{  1, 0x0f3a, 0, {0x22} },
-{ 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} },
-{ 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} },
-{ 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} },
-{ 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} },
-{ 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} },
-{ 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} },
-{ 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} },
-{ 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} },
-{ 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} },
-{ 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} },
-{ 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} },
-{ 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} },
-{ 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} },
-{ 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} },
-{ 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} },
-{ 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} },
-{  4, 0x1017, 0, {0x00,0x03,0x01,0x00} },
-{  2, 0x101b, 0, {0x7a,0x00} },
-{  3, 0x101d, 0, {0xba,0x05,0x00} },
-{  2, 0x1020, 0, {0x50,0x17} },
-{  8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} },
-{  5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} },
-{ 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} },
-{  3, 0x1039, 0, {0x90,0x00,0x01} },
-{  1, 0x103c, 0, {0x22} },
-{ 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} },
-{  4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} },
-{ 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} },
-{  4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} },
-{  8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} },
-{  1, 0x1069, 0, {0x22} },
-{ 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} },
-{  4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} },
-{ 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} },
-{  4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} },
-{  1, 0x108e, 0, {0x22} },
-{ 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} },
-{ 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} },
-{  5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} },
-{ 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} },
-{  6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} },
-{  6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} },
-{  1, 0x10c9, 0, {0x22} },
-{  8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} },
-{  3, 0x10d2, 0, {0xba,0xff,0x00} },
-{  2, 0x10d5, 0, {0x50,0x0a} },
-{ 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
-{  1, 0x10e1, 0, {0x22} },
-{  5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} },
-{  8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} },
-{  6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} },
-{  4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} },
-{ 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} },
-{  5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x1109, 0, {0x80,0xee} },
-{  1, 0x110b, 0, {0x22} },
-{ 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} },
-{  3, 0x1116, 0, {0xba,0x28,0x00} },
-{  2, 0x1119, 0, {0x50,0x03} },
-{  3, 0x111b, 0, {0x0a,0x80,0xf8} },
-{  5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} },
-{  8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} },
-{  5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} },
-{  9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} },
-{  2, 0x1139, 0, {0x7a,0x00} },
-{  3, 0x113b, 0, {0xba,0x28,0x00} },
-{  2, 0x113e, 0, {0x50,0x03} },
-{  3, 0x1140, 0, {0x0a,0x80,0xf8} },
-{  1, 0x1143, 0, {0x22} },
-{  4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} },
-{  2, 0x1148, 0, {0x80,0x07} },
-{  7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} },
-{  5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} },
-{  9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} },
-{ 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} },
-{  8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} },
-{  3, 0x1171, 0, {0x0a,0x80,0xf5} },
-{  1, 0x1174, 0, {0x22} },
-{  6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} },
-{ 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} },
-{ 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} },
-{  9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x119d, 0, {0x80,0xdc} },
-{  1, 0x119f, 0, {0x22} },
-{ 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} },
-{  2, 0x11ad, 0, {0x50,0x06} },
-{  6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
-{  4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} },
-{ 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} },
-{  8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} },
-{  6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
-{  4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} },
-{  5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} },
-{  1, 0x11dc, 0, {0x22} },
-{  7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} },
-{ 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} },
-{  3, 0x11f0, 0, {0x12,0x11,0x44} },
-{ 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} },
-{  5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} },
-{  1, 0x1204, 0, {0x22} },
-{  2, 0x1205, 0, {0x7a,0x04} },
-{  3, 0x1207, 0, {0xba,0x40,0x00} },
-{  2, 0x120a, 0, {0x50,0x36} },
-{ 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} },
-{  3, 0x121a, 0, {0xbc,0x08,0x00} },
-{  2, 0x121d, 0, {0x50,0x20} },
-{  6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} },
-{ 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} },
-{  8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} },
-{  7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} },
-{  3, 0x123f, 0, {0x0a,0x80,0xc5} },
-{  1, 0x1242, 0, {0x22} },
-{  4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} },
-{  3, 0x1247, 0, {0xba,0x10,0x00} },
-{  2, 0x124a, 0, {0x50,0x20} },
-{ 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} },
-{ 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} },
-{  4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} },
-{  1, 0x126c, 0, {0x22} },
-{ 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{  1, 0x12b3, 0, {0x22} },
-{ 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} },
-{ 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} },
-{ 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} },
-{ 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} },
-{ 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} },
-{ 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} },
-{ 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} },
-{ 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} },
-{ 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} },
-{ 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} },
-{ 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} },
-{ 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} },
-{  3, 0x135c, 0, {0xbd,0x06,0x00} },
-{  2, 0x135f, 0, {0x50,0x12} },
-{ 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
-{  7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} },
-{ 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} },
-{ 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} },
-{ 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} },
-{  6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} },
-{  1, 0x13a2, 0, {0x22} },
-{ 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} },
-{ 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} },
-{  3, 0x13be, 0, {0xfa,0x7b,0x00} },
-{  3, 0x13c1, 0, {0xbb,0x10,0x00} },
-{  2, 0x13c4, 0, {0x50,0x24} },
-{ 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} },
-{ 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} },
-{  8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} },
-{ 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} },
-{  5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} },
-{  1, 0x13fd, 0, {0x22} },
-{  4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} },
-{  2, 0x1402, 0, {0x80,0x16} },
-{ 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} },
-{ 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} },
-{ 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} },
-{  6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} },
-{  6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} },
-{ 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} },
-{  1, 0x143b, 0, {0xe4} },
-{  3, 0x143c, 0, {0xfa,0x70,0x0f} },
-{ 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} },
-{  3, 0x144b, 0, {0x02,0x80,0x0a} },
-{ 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} },
-{ 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} },
-{  4, 0x1464, 0, {0x02,0xea,0x70,0x1a} },
-{ 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} },
-{  9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} },
-{  4, 0x147e, 0, {0x11,0x75,0x80,0x36} },
-{  2, 0x1482, 0, {0x7a,0x00} },
-{  3, 0x1484, 0, {0xba,0x10,0x00} },
-{  2, 0x1487, 0, {0x50,0x2f} },
-{ 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} },
-{  4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} },
-{ 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} },
-{  9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} },
-{  4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} },
-{  3, 0x14b5, 0, {0x0a,0x80,0xcc} },
-{  1, 0x14b8, 0, {0x22} },
-{  6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} },
-{ 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} },
-{  7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} },
-{  7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} },
-{  5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} },
-{  4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} },
-{  5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} },
-{  4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} },
-{  1, 0x14ed, 0, {0x22} },
-{ 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} },
-{  6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} },
-{  5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} },
-{  3, 0x1507, 0, {0xe0,0x80,0x07} },
-{  4, 0x150a, 0, {0xe4,0x93,0x80,0x03} },
-{  3, 0x150e, 0, {0xa8,0x82,0xe2} },
-{  4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} },
-{  1, 0x1515, 0, {0x22} },
-{  0, 0x0000, 1, {0} }
-
-};
-
-static unsigned char bitstream[] = {
-
-0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D,
-0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B,
-0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39,
-0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34,
-0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B,
-0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F,
-0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF,
-0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB,
-0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF,
-0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE,
-0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF,
-0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF,
-0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,
-0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF,
-0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD,
-0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB,
-0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,
-0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF,
-0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
-0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D,
-0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
-0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE,
-0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF,
-0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F,
-0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F,
-0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF,
-0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,
-0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F,
-0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F,
-0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2,
-0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF,
-0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF,
-0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE,
-0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF,
-0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF,
-0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B,
-0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF,
-0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7,
-0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF,
-0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF,
-0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5,
-0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD,
-0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF,
-0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF,
-0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B,
-0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF,
-0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED,
-0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF,
-0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB,
-0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF,
-0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE,
-0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7,
-0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE,
-0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF,
-0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD,
-0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD,
-0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF,
-0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD,
-0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A,
-0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF,
-0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF,
-0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA,
-0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF,
-0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD,
-0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF,
-0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,
-0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E,
-0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF,
-0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF,
-0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF,
-0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF,
-0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3,
-0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF,
-0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F,
-0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF,
-0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF,
-0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7,
-0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF,
-0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF,
-0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD,
-0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD,
-0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE,
-0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF,
-0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF,
-0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3,
-0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A,
-0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6,
-0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF,
-0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB,
-0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF,
-0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD,
-0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB,
-0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,
-0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF,
-0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,
-0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F,
-0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
-0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F,
-0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
-0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED,
-0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
-0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF,
-0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7,
-0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7,
-0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF,
-0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F,
-0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE,
-0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
-0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
-0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA,
-0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F,
-0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA,
-0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB,
-0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF,
-0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB,
-0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F,
-0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF,
-0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF,
-0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD,
-0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF,
-0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF,
-0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C,
-0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF,
-0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF,
-0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD,
-0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF,
-0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3,
-0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB,
-0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F,
-0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3,
-0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF,
-0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7,
-0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7,
-0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF,
-0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE,
-0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF,
-0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB,
-0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66,
-0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE,
-0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6,
-0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED,
-0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD,
-0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7,
-0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF,
-0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB,
-0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF,
-0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F,
-0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7,
-0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9,
-0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF,
-0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF,
-0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE,
-0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF,
-0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF,
-0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF,
-0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF,
-0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD,
-0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1,
-0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF,
-0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5,
-0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF,
-0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB,
-0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF,
-0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF,
-0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3,
-0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE,
-0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD,
-0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE,
-0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF,
-0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF,
-0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB,
-0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF,
-0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF,
-0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF,
-0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F,
-0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C,
-0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD,
-0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF,
-0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F,
-0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE,
-0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD,
-0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54,
-0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2,
-0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD,
-0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF,
-0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF,
-0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7,
-0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA,
-0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF,
-0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C,
-0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF,
-0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5,
-0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB,
-0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF,
-0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF,
-0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F,
-0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F,
-0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF,
-0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF,
-0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5,
-0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF,
-0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF,
-0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A,
-0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36,
-0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF,
-0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F,
-0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F,
-0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF,
-0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF,
-0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF,
-0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF,
-0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE,
-0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,
-0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF,
-0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F,
-0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B,
-0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF,
-0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB,
-0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF,
-0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF,
-0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA,
-0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37,
-0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD,
-0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B,
-0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF,
-0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B,
-0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B,
-0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF,
-0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF,
-0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD,
-0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF,
-0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE,
-0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF,
-0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF,
-0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA,
-0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E,
-0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF,
-0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF,
-0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6,
-0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD,
-0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB,
-0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F,
-0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F,
-0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7,
-0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
-0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB,
-0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD,
-0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E,
-0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF,
-0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE,
-0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF,
-0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF,
-0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE,
-0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2,
-0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
-0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF,
-0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF,
-0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF,
-0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC,
-0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF,
-0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7,
-0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7,
-0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3,
-0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9,
-0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF,
-0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,
-0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6,
-0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F,
-0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B,
-0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE,
-0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79,
-0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F,
-0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7,
-0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC,
-0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB,
-0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7,
-0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF,
-0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF,
-0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,
-0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F,
-0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE,
-0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF,
-0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F,
-0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7,
-0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7,
-0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF,
-0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,
-0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD,
-0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF,
-0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB,
-0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE,
-0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3,
-0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF,
-0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF,
-0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE,
-0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6,
-0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF,
-0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF,
-0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F,
-0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE,
-0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6,
-0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77,
-0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF,
-0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A,
-0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F,
-0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F,
-0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF,
-0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB,
-0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F,
-0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67,
-0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF,
-0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D,
-0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3,
-0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D,
-0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB,
-0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE,
-0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5,
-0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,
-0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D,
-0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F,
-0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB,
-0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB,
-0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9,
-0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF,
-0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF,
-0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF,
-0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77,
-0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F,
-0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE,
-0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
-0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF,
-0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD,
-0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F,
-0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A,
-0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA,
-0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF,
-0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF,
-0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF,
-0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF,
-0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF,
-0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF,
-0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9,
-0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F,
-0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7,
-0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4,
-0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE,
-0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9,
-0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF,
-0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7,
-0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF,
-0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF,
-0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF,
-0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5,
-0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF,
-0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD,
-0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77,
-0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE,
-0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF,
-0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF,
-0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC,
-0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB,
-0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F,
-0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6,
-0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD,
-0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF,
-0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC,
-0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,
-0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF,
-0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E,
-0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F,
-0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB,
-0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF,
-0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7,
-0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F,
-0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
-0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2,
-0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA,
-0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF,
-0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8,
-0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB,
-0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF,
-0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB,
-0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF,
-0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF,
-0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7,
-0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3,
-0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F,
-0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD,
-0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF,
-0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
-0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF,
-0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF,
-0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F,
-0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF,
-0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F,
-0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF,
-0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7,
-0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9,
-0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71,
-0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF,
-0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF,
-0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F,
-0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7,
-0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC,
-0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE,
-0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7,
-0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF,
-0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB,
-0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B,
-0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF,
-0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF,
-0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE,
-0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17,
-0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9,
-0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F,
-0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE,
-0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,
-0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F,
-0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF,
-0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF,
-0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F,
-0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF,
-0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5,
-0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA,
-0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE,
-0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF,
-0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA,
-0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3,
-0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,
-0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7,
-0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
-0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF,
-0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB,
-0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE,
-0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9,
-0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF,
-0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD,
-0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE,
-0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE,
-0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB,
-0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB,
-0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB,
-0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF,
-0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF,
-0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77,
-0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE,
-0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8,
-0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E,
-0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3,
-0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,
-0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7,
-0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB,
-0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF,
-0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF,
-0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF,
-0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3,
-0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F,
-0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F,
-0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF,
-0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,
-0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF,
-0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF,
-0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD,
-0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE,
-0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1,
-0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF,
-0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC,
-0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF,
-0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB,
-0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9,
-0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E,
-0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF,
-0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,
-0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,
-0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF,
-0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7,
-0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF,
-0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F,
-0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF,
-0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF,
-0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF,
-0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3,
-0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC,
-0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF,
-0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF,
-0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF,
-0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF,
-0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF,
-0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF,
-0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA,
-0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF,
-0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF,
-0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF,
-0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF,
-0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB,
-0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F,
-0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF,
-0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD,
-0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD,
-0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE,
-0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF,
-0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5,
-0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F,
-0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF,
-0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE,
-0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB,
-0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF,
-0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF,
-0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF,
-0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF,
-0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB,
-0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7,
-0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF,
-0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F,
-0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
-0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF,
-0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB,
-0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF,
-0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF,
-0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF,
-0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,
-0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,
-0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF,
-0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE,
-0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
-0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE,
-0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4,
-0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC,
-0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF,
-0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7,
-0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65,
-0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3,
-0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,
-0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,
-0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB,
-0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF,
-0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B,
-0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF,
-0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF,
-0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF,
-0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7,
-0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF,
-0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9,
-0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,
-0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF,
-0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF,
-0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,
-0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A,
-0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7,
-0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF,
-0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD,
-0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC,
-0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA,
-0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D,
-0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF,
-0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6,
-0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
-0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF,
-0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF,
-0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF,
-0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF,
-0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB,
-0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E,
-0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF,
-0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF,
-0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF,
-0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF,
-0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16,
-0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF,
-0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7,
-0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9,
-0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF,
-0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F,
-0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A,
-0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE,
-0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB,
-0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB,
-0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3,
-0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF,
-0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE,
-0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB,
-0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF,
-0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE,
-0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5,
-0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF,
-0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,
-0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD,
-0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F,
-0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7,
-0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
-0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA,
-0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD,
-0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
-0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA,
-0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33,
-0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9,
-0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF,
-0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77,
-0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF,
-0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F,
-0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF,
-0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF,
-0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7,
-0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF,
-0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,
-0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB,
-0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF,
-0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD,
-0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE,
-0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF,
-0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F,
-0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B,
-0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9,
-0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF,
-0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD,
-0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF,
-0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
-0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB,
-0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF,
-0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF,
-0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF,
-0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9,
-0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF,
-0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD,
-0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE,
-0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF,
-0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF,
-0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,
-0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE,
-0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE,
-0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF,
-0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF,
-0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF,
-0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF,
-0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF,
-0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF,
-0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD,
-0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF,
-0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F,
-0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF,
-0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE,
-0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB,
-0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF,
-0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF,
-0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5,
-0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF,
-0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
-0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF,
-0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB,
-0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7,
-0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF,
-0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE,
-0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB,
-0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,
-0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF,
-0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB,
-0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF,
-0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7,
-0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F,
-0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF,
-0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF,
-0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F,
-0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD,
-0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF,
-0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF,
-0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF,
-0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7,
-0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,
-0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,
-0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC,
-0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC,
-0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF,
-0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF,
-0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB,
-0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD,
-0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF
-
-};
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
deleted file mode 100644 (file)
index 1774ab7..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      dabusb.c  --  dab usb driver.
- *
- *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.de)
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *
- *  $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/socket.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/smp_lock.h>
-#include <linux/mutex.h>
-
-#include "dabusb.h"
-#include "dabfirmware.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.54"
-#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
-#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
-
-/* --------------------------------------------------------------------- */
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define NRDABUSB 256
-#else
-#define NRDABUSB 4
-#endif
-
-/*-------------------------------------------------------------------*/
-
-static dabusb_t dabusb[NRDABUSB];
-static int buffers = 256;
-static struct usb_driver dabusb_driver;
-
-/*-------------------------------------------------------------------*/
-
-static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src)
-{
-       unsigned long flags;
-       struct list_head *tmp;
-       int ret = 0;
-
-       spin_lock_irqsave (&s->lock, flags);
-
-       if (list_empty (src)) {
-               // no elements in source buffer
-               ret = -1;
-               goto err;
-       }
-       tmp = src->next;
-       list_move_tail (tmp, dst);
-
-  err: spin_unlock_irqrestore (&s->lock, flags);
-       return ret;
-}
-/*-------------------------------------------------------------------*/
-#ifdef DEBUG 
-static void dump_urb (struct urb *urb)
-{
-       dbg("urb                   :%p", urb);
-       dbg("dev                   :%p", urb->dev);
-       dbg("pipe                  :%08X", urb->pipe);
-       dbg("status                :%d", urb->status);
-       dbg("transfer_flags        :%08X", urb->transfer_flags);
-       dbg("transfer_buffer       :%p", urb->transfer_buffer);
-       dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
-       dbg("actual_length         :%d", urb->actual_length);
-       dbg("setup_packet          :%p", urb->setup_packet);
-       dbg("start_frame           :%d", urb->start_frame);
-       dbg("number_of_packets     :%d", urb->number_of_packets);
-       dbg("interval              :%d", urb->interval);
-       dbg("error_count           :%d", urb->error_count);
-       dbg("context               :%p", urb->context);
-       dbg("complete              :%p", urb->complete);
-}
-#endif
-/*-------------------------------------------------------------------*/
-static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
-{
-       unsigned long flags;
-       pbuff_t b;
-
-       dbg("dabusb_cancel_queue");
-
-       spin_lock_irqsave (&s->lock, flags);
-
-       list_for_each_entry(b, q, buff_list) {
-#ifdef DEBUG
-               dump_urb(b->purb);
-#endif
-               usb_unlink_urb (b->purb);
-       }
-       spin_unlock_irqrestore (&s->lock, flags);
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_queue (struct list_head *q)
-{
-       struct list_head *tmp;
-       struct list_head *p;
-       pbuff_t b;
-
-       dbg("dabusb_free_queue");
-       for (p = q->next; p != q;) {
-               b = list_entry (p, buff_t, buff_list);
-
-#ifdef DEBUG 
-               dump_urb(b->purb);
-#endif
-               kfree(b->purb->transfer_buffer);
-               usb_free_urb(b->purb);
-               tmp = p->next;
-               list_del (p);
-               kfree (b);
-               p = tmp;
-       }
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_buffers (pdabusb_t s)
-{
-       unsigned long flags;
-       dbg("dabusb_free_buffers");
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       dabusb_free_queue (&s->free_buff_list);
-       dabusb_free_queue (&s->rec_buff_list);
-
-       spin_unlock_irqrestore(&s->lock, flags);
-
-       s->got_mem = 0;
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)
-{
-       pbuff_t b = purb->context;
-       pdabusb_t s = b->s;
-       int i;
-       int len;
-       int dst = 0;
-       void *buf = purb->transfer_buffer;
-
-       dbg("dabusb_iso_complete");
-
-       // process if URB was not killed
-       if (purb->status != -ENOENT) {
-               unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
-               int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
-               for (i = 0; i < purb->number_of_packets; i++)
-                       if (!purb->iso_frame_desc[i].status) {
-                               len = purb->iso_frame_desc[i].actual_length;
-                               if (len <= pipesize) {
-                                       memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);
-                                       dst += len;
-                               }
-                               else
-                                       err("dabusb_iso_complete: invalid len %d", len);
-                       }
-                       else
-                               warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status);
-               if (dst != purb->actual_length)
-                       err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
-       }
-
-       if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
-               s->overruns++;
-               err("overrun (%d)", s->overruns);
-       }
-       wake_up (&s->wait);
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_alloc_buffers (pdabusb_t s)
-{
-       int buffers = 0;
-       pbuff_t b;
-       unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
-       int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
-       int packets = _ISOPIPESIZE / pipesize;
-       int transfer_buffer_length = packets * pipesize;
-       int i;
-
-       dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
-                pipesize, packets, transfer_buffer_length);
-
-       while (buffers < (s->total_buffer_size << 10)) {
-               b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
-               if (!b) {
-                       err("kzalloc(sizeof(buff_t))==NULL");
-                       goto err;
-               }
-               b->s = s;
-               b->purb = usb_alloc_urb(packets, GFP_KERNEL);
-               if (!b->purb) {
-                       err("usb_alloc_urb == NULL");
-                       kfree (b);
-                       goto err;
-               }
-
-               b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);
-               if (!b->purb->transfer_buffer) {
-                       kfree (b->purb);
-                       kfree (b);
-                       err("kmalloc(%d)==NULL", transfer_buffer_length);
-                       goto err;
-               }
-
-               b->purb->transfer_buffer_length = transfer_buffer_length;
-               b->purb->number_of_packets = packets;
-               b->purb->complete = dabusb_iso_complete;
-               b->purb->context = b;
-               b->purb->dev = s->usbdev;
-               b->purb->pipe = pipe;
-               b->purb->transfer_flags = URB_ISO_ASAP;
-
-               for (i = 0; i < packets; i++) {
-                       b->purb->iso_frame_desc[i].offset = i * pipesize;
-                       b->purb->iso_frame_desc[i].length = pipesize;
-               }
-
-               buffers += transfer_buffer_length;
-               list_add_tail (&b->buff_list, &s->free_buff_list);
-       }
-       s->got_mem = buffers;
-
-       return 0;
-
-       err:
-       dabusb_free_buffers (s);
-       return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
-{
-       int ret;
-       unsigned int pipe;
-       int actual_length;
-
-       dbg("dabusb_bulk");
-
-       if (!pb->pipe)
-               pipe = usb_rcvbulkpipe (s->usbdev, 2);
-       else
-               pipe = usb_sndbulkpipe (s->usbdev, 2);
-
-       ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
-       if(ret<0) {
-               err("dabusb: usb_bulk_msg failed(%d)",ret);
-
-               if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-                       err("set_interface failed");
-                       return -EINVAL;
-               }
-
-       }
-       
-       if( ret == -EPIPE ) {
-               warn("CLEAR_FEATURE request to remove STALL condition.");
-               if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
-                       err("request failed");
-       }
-
-       pb->size = actual_length;
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len)
-{
-       int ret;
-       unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);
-
-       if (!transfer_buffer) {
-               err("dabusb_writemem: kmalloc(%d) failed.", len);
-               return -ENOMEM;
-       }
-
-       memcpy (transfer_buffer, data, len);
-
-       ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
-
-       kfree (transfer_buffer);
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit)
-{
-       dbg("dabusb_8051_reset: %d",reset_bit);
-       return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_loadmem (pdabusb_t s, const char *fname)
-{
-       int ret;
-       PINTEL_HEX_RECORD ptr = firmware;
-
-       dbg("Enter dabusb_loadmem (internal)");
-       
-       ret = dabusb_8051_reset (s, 1);
-       while (ptr->Type == 0) {
-
-               dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length);
-
-               ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length);
-               if (ret < 0) {
-                       err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length);
-                       break;
-               }
-               ptr++;
-       }
-       ret = dabusb_8051_reset (s, 0);
-
-       dbg("dabusb_loadmem: exit");
-
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b)
-{
-       b->size = 4;
-       b->data[0] = 0x2a;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 0;
-
-       dbg("dabusb_fpga_clear");
-
-       return dabusb_bulk (s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b)
-{
-       b->size = 4;
-       b->data[0] = 0x2c;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 0;
-
-       dbg("dabusb_fpga_init");
-
-       return dabusb_bulk (s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_download (pdabusb_t s, const char *fname)
-{
-       pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
-       unsigned int blen, n;
-       int ret;
-       unsigned char *buf = bitstream;
-
-       dbg("Enter dabusb_fpga_download (internal)");
-
-       if (!b) {
-               err("kmalloc(sizeof(bulk_transfer_t))==NULL");
-               return -ENOMEM;
-       }
-
-       b->pipe = 1;
-       ret = dabusb_fpga_clear (s, b);
-       mdelay (10);
-       blen = buf[73] + (buf[72] << 8);
-
-       dbg("Bitstream len: %i", blen);
-
-       b->data[0] = 0x2b;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 60;
-
-       for (n = 0; n <= blen + 60; n += 60) {
-               // some cclks for startup
-               b->size = 64;
-               memcpy (b->data + 4, buf + 74 + n, 60);
-               ret = dabusb_bulk (s, b);
-               if (ret < 0) {
-                       err("dabusb_bulk failed.");
-                       break;
-               }
-               mdelay (1);
-       }
-
-       ret = dabusb_fpga_init (s, b);
-       kfree (b);
-
-       dbg("exit dabusb_fpga_download");
-
-       return ret;
-}
-
-static int dabusb_stop (pdabusb_t s)
-{
-       dbg("dabusb_stop");
-
-       s->state = _stopped;
-       dabusb_cancel_queue (s, &s->rec_buff_list);
-
-       dbg("pending_io: %d", s->pending_io.counter);
-
-       s->pending_io.counter = 0;
-       return 0;
-}
-
-static int dabusb_startrek (pdabusb_t s)
-{
-       if (!s->got_mem && s->state != _started) {
-
-               dbg("dabusb_startrek");
-
-               if (dabusb_alloc_buffers (s) < 0)
-                       return -ENOMEM;
-               dabusb_stop (s);
-               s->state = _started;
-               s->readptr = 0;
-       }
-
-       if (!list_empty (&s->free_buff_list)) {
-               pbuff_t end;
-               int ret;
-               
-       while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) {
-
-                       dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
-
-                       end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
-
-                       ret = usb_submit_urb (end->purb, GFP_KERNEL);
-                       if (ret) {
-                               err("usb_submit_urb returned:%d", ret);
-                               if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
-                                       err("startrek: dabusb_add_buf_tail failed");
-                               break;
-                       }
-                       else
-                               atomic_inc (&s->pending_io);
-               }
-               dbg("pending_io: %d",s->pending_io.counter);
-       }
-
-       return 0;
-}
-
-static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
-{
-       pdabusb_t s = (pdabusb_t) file->private_data;
-       unsigned long flags;
-       unsigned ret = 0;
-       int rem;
-       int cnt;
-       pbuff_t b;
-       struct urb *purb = NULL;
-
-       dbg("dabusb_read");
-
-       if (*ppos)
-               return -ESPIPE;
-
-       if (s->remove_pending)
-               return -EIO;
-
-
-       if (!s->usbdev)
-               return -EIO;
-
-       while (count > 0) {
-               dabusb_startrek (s);
-
-               spin_lock_irqsave (&s->lock, flags);
-
-               if (list_empty (&s->rec_buff_list)) {
-
-                       spin_unlock_irqrestore(&s->lock, flags);
-
-                       err("error: rec_buf_list is empty");
-                       goto err;
-               }
-               
-               b = list_entry (s->rec_buff_list.next, buff_t, buff_list);
-               purb = b->purb;
-
-               spin_unlock_irqrestore(&s->lock, flags);
-
-               if (purb->status == -EINPROGRESS) {
-                       if (file->f_flags & O_NONBLOCK)         // return nonblocking
-                        {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               goto err;
-                       }
-
-                       interruptible_sleep_on (&s->wait);
-
-                       if (signal_pending (current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               goto err;
-                       }
-
-                       spin_lock_irqsave (&s->lock, flags);
-
-                       if (list_empty (&s->rec_buff_list)) {
-                               spin_unlock_irqrestore(&s->lock, flags);
-                               err("error: still no buffer available.");
-                               goto err;
-                       }
-                       spin_unlock_irqrestore(&s->lock, flags);
-                       s->readptr = 0;
-               }
-               if (s->remove_pending) {
-                       ret = -EIO;
-                       goto err;
-               }
-
-               rem = purb->actual_length - s->readptr;         // set remaining bytes to copy
-
-               if (count >= rem)
-                       cnt = rem;
-               else
-                       cnt = count;
-
-               dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
-
-               if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
-                       err("read: copy_to_user failed");
-                       if (!ret)
-                               ret = -EFAULT;
-                       goto err;
-               }
-
-               s->readptr += cnt;
-               count -= cnt;
-               buf += cnt;
-               ret += cnt;
-
-               if (s->readptr == purb->actual_length) {
-                       // finished, take next buffer
-                       if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
-                               err("read: dabusb_add_buf_tail failed");
-                       s->readptr = 0;
-               }
-       }
-      err:                     //mutex_unlock(&s->mutex);
-       return ret;
-}
-
-static int dabusb_open (struct inode *inode, struct file *file)
-{
-       int devnum = iminor(inode);
-       pdabusb_t s;
-
-       if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
-               return -EIO;
-
-       s = &dabusb[devnum - DABUSB_MINOR];
-
-       dbg("dabusb_open");
-       mutex_lock(&s->mutex);
-
-       while (!s->usbdev || s->opened) {
-               mutex_unlock(&s->mutex);
-
-               if (file->f_flags & O_NONBLOCK) {
-                       return -EBUSY;
-               }
-               msleep_interruptible(500);
-
-               if (signal_pending (current)) {
-                       return -EAGAIN;
-               }
-               mutex_lock(&s->mutex);
-       }
-       if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-               mutex_unlock(&s->mutex);
-               err("set_interface failed");
-               return -EINVAL;
-       }
-       s->opened = 1;
-       mutex_unlock(&s->mutex);
-
-       file->f_pos = 0;
-       file->private_data = s;
-
-       return nonseekable_open(inode, file);
-}
-
-static int dabusb_release (struct inode *inode, struct file *file)
-{
-       pdabusb_t s = (pdabusb_t) file->private_data;
-
-       dbg("dabusb_release");
-
-       mutex_lock(&s->mutex);
-       dabusb_stop (s);
-       dabusb_free_buffers (s);
-       mutex_unlock(&s->mutex);
-
-       if (!s->remove_pending) {
-               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
-                       err("set_interface failed");
-       }
-       else
-               wake_up (&s->remove_ok);
-
-       s->opened = 0;
-       return 0;
-}
-
-static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       pdabusb_t s = (pdabusb_t) file->private_data;
-       pbulk_transfer_t pbulk;
-       int ret = 0;
-       int version = DABUSB_VERSION;
-
-       dbg("dabusb_ioctl");
-
-       if (s->remove_pending)
-               return -EIO;
-
-       mutex_lock(&s->mutex);
-
-       if (!s->usbdev) {
-               mutex_unlock(&s->mutex);
-               return -EIO;
-       }
-
-       switch (cmd) {
-
-       case IOCTL_DAB_BULK:
-               pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
-
-               if (!pbulk) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
-                       ret = -EFAULT;
-                       kfree (pbulk);
-                       break;
-               }
-
-               ret=dabusb_bulk (s, pbulk);
-               if(ret==0)
-                       if (copy_to_user((void __user *)arg, pbulk,
-                                        sizeof(bulk_transfer_t)))
-                               ret = -EFAULT;
-               kfree (pbulk);
-               break;
-
-       case IOCTL_DAB_OVERRUNS:
-               ret = put_user (s->overruns, (unsigned int __user *) arg);
-               break;
-
-       case IOCTL_DAB_VERSION:
-               ret = put_user (version, (unsigned int __user *) arg);
-               break;
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-       mutex_unlock(&s->mutex);
-       return ret;
-}
-
-static struct file_operations dabusb_fops =
-{
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .read =         dabusb_read,
-       .ioctl =        dabusb_ioctl,
-       .open =         dabusb_open,
-       .release =      dabusb_release,
-};
-
-static struct usb_class_driver dabusb_class = {
-       .name =         "dabusb%d",
-       .fops =         &dabusb_fops,
-       .minor_base =   DABUSB_MINOR,
-};
-
-
-/* --------------------------------------------------------------------- */
-static int dabusb_probe (struct usb_interface *intf,
-                        const struct usb_device_id *id)
-{
-       struct usb_device *usbdev = interface_to_usbdev(intf);
-       int retval;
-       pdabusb_t s;
-
-       dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
-           le16_to_cpu(usbdev->descriptor.idVendor),
-           le16_to_cpu(usbdev->descriptor.idProduct),
-           intf->altsetting->desc.bInterfaceNumber);
-
-       /* We don't handle multiple configurations */
-       if (usbdev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF &&
-           le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999)
-               return -ENODEV;
-
-
-
-       s = &dabusb[intf->minor];
-
-       mutex_lock(&s->mutex);
-       s->remove_pending = 0;
-       s->usbdev = usbdev;
-       s->devnum = intf->minor;
-
-       if (usb_reset_configuration (usbdev) < 0) {
-               err("reset_configuration failed");
-               goto reject;
-       }
-       if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
-               dabusb_loadmem (s, NULL);
-               goto reject;
-       }
-       else {
-               dabusb_fpga_download (s, NULL);
-
-               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
-                       err("set_interface failed");
-                       goto reject;
-               }
-       }
-       dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
-       usb_set_intfdata (intf, s);
-       mutex_unlock(&s->mutex);
-
-       retval = usb_register_dev(intf, &dabusb_class);
-       if (retval) {
-               usb_set_intfdata (intf, NULL);
-               return -ENOMEM;
-       }
-
-       return 0;
-
-      reject:
-       mutex_unlock(&s->mutex);
-       s->usbdev = NULL;
-       return -ENODEV;
-}
-
-static void dabusb_disconnect (struct usb_interface *intf)
-{
-       wait_queue_t __wait;
-       pdabusb_t s = usb_get_intfdata (intf);
-
-       dbg("dabusb_disconnect");
-       
-       init_waitqueue_entry(&__wait, current);
-       
-       usb_set_intfdata (intf, NULL);
-       if (s) {
-               usb_deregister_dev (intf, &dabusb_class);
-               s->remove_pending = 1;
-               wake_up (&s->wait);
-               add_wait_queue(&s->remove_ok, &__wait);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               if (s->state == _started)
-                       schedule();
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&s->remove_ok, &__wait);
-               
-               s->usbdev = NULL;
-               s->overruns = 0;
-       }
-}
-
-static struct usb_device_id dabusb_ids [] = {
-       // { USB_DEVICE(0x0547, 0x2131) },      /* An2131 chip, no boot ROM */
-       { USB_DEVICE(0x0547, 0x9999) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, dabusb_ids);
-
-static struct usb_driver dabusb_driver = {
-       .name =         "dabusb",
-       .probe =        dabusb_probe,
-       .disconnect =   dabusb_disconnect,
-       .id_table =     dabusb_ids,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int __init dabusb_init (void)
-{
-       int retval;
-       unsigned u;
-
-       /* initialize struct */
-       for (u = 0; u < NRDABUSB; u++) {
-               pdabusb_t s = &dabusb[u];
-               memset (s, 0, sizeof (dabusb_t));
-               mutex_init (&s->mutex);
-               s->usbdev = NULL;
-               s->total_buffer_size = buffers;
-               init_waitqueue_head (&s->wait);
-               init_waitqueue_head (&s->remove_ok);
-               spin_lock_init (&s->lock);
-               INIT_LIST_HEAD (&s->free_buff_list);
-               INIT_LIST_HEAD (&s->rec_buff_list);
-       }
-
-       /* register misc device */
-       retval = usb_register(&dabusb_driver);
-       if (retval)
-               goto out;
-
-       dbg("dabusb_init: driver registered");
-
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-
-out:
-       return retval;
-}
-
-static void __exit dabusb_cleanup (void)
-{
-       dbg("dabusb_cleanup");
-
-       usb_deregister (&dabusb_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
-module_param(buffers, int, 0);
-MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
-
-module_init (dabusb_init);
-module_exit (dabusb_cleanup);
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h
deleted file mode 100644 (file)
index 96b03e4..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#define _BULK_DATA_LEN 64
-typedef struct
-{
-       unsigned char data[_BULK_DATA_LEN];
-       unsigned int size;
-       unsigned int pipe;
-}bulk_transfer_t,*pbulk_transfer_t;
-
-#define DABUSB_MINOR 240               /* some unassigned USB minor */
-#define DABUSB_VERSION 0x1000
-#define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
-#define IOCTL_DAB_OVERRUNS         _IOR('d',  0x15, int)
-#define IOCTL_DAB_VERSION           _IOR('d', 0x3f, int) 
-
-#ifdef __KERNEL__
-
-typedef enum { _stopped=0, _started } driver_state_t;
-
-typedef struct
-{
-       struct mutex mutex;
-       struct usb_device *usbdev;
-       wait_queue_head_t wait;
-       wait_queue_head_t remove_ok;
-       spinlock_t lock;
-       atomic_t pending_io;
-       driver_state_t state;
-       int remove_pending;
-       int got_mem;
-       int total_buffer_size;
-       unsigned int overruns;
-       int readptr;
-       int opened;
-       int devnum;
-       struct list_head free_buff_list;
-       struct list_head rec_buff_list;
-} dabusb_t,*pdabusb_t;
-
-typedef struct 
-{
-       pdabusb_t s;
-       struct urb *purb;
-       struct list_head buff_list;
-} buff_t,*pbuff_t;
-
-typedef struct
-{
-       wait_queue_head_t wait;
-} bulk_completion_context_t, *pbulk_completion_context_t;
-
-
-#define _DABUSB_IF 2
-#define _DABUSB_ISOPIPE 0x09
-#define _ISOPIPESIZE   16384
-
-#define _BULK_DATA_LEN 64
-// Vendor specific request code for Anchor Upload/Download
-// This one is implemented in the core
-#define ANCHOR_LOAD_INTERNAL  0xA0
-
-// EZ-USB Control and Status Register.  Bit 0 controls 8051 reset
-#define CPUCS_REG    0x7F92
-#define _TOTAL_BUFFERS 384
-
-#define MAX_INTEL_HEX_RECORD_LENGTH 16
-
-#ifndef _BYTE_DEFINED
-#define _BYTE_DEFINED
-typedef unsigned char BYTE;
-#endif // !_BYTE_DEFINED
-
-#ifndef _WORD_DEFINED
-#define _WORD_DEFINED
-typedef unsigned short WORD;
-#endif // !_WORD_DEFINED
-
-typedef struct _INTEL_HEX_RECORD
-{
-   BYTE  Length;
-   WORD  Address;
-   BYTE  Type;
-   BYTE  Data[MAX_INTEL_HEX_RECORD_LENGTH];
-} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
-
-#endif
diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c
deleted file mode 100644 (file)
index 2564680..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
- into both the USB and an analog audio input, so this thing
- only deals with initialisation and frequency setting, the
- audio data has to be handled by a sound driver.
-
- Major issue: I can't find out where the device reports the signal
- strength, and indeed the windows software appearantly just looks
- at the stereo indicator as well.  So, scanning will only find
- stereo stations.  Sad, but I can't help it.
-
- Also, the windows program sends oodles of messages over to the
- device, and I couldn't figure out their meaning.  My suspicion
- is that they don't have any:-)
-
- You might find some interesting stuff about this module at
- http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
-
- Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- History:
-
- Version 0.40:
-  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
-
- Version 0.30:
-       Markus: Updates for 2.5.x kernel and more ISO compliant source
-
- Version 0.25:
-        PSL and Markus: Cleanup, radio now doesn't stop on device close
-
- Version 0.24:
-       Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
-       right.  Some minor cleanup, improved standalone compilation
-
- Version 0.23:
-       Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
-
- Version 0.22:
-       Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, 
-       thanks to Mike Cox for pointing the problem out.
-
- Version 0.21:
-       Markus: Minor cleanup, warnings if something goes wrong, lame attempt
-       to adhere to Documentation/CodingStyle
-
- Version 0.2: 
-       Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
-       Markus: Copyright clarification
-
- Version 0.01: Markus: initial release
-
-*/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/smp_lock.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.40"
-#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
-#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
-
-#define DSB100_VENDOR 0x04b4
-#define DSB100_PRODUCT 0x1002
-
-/* Commands the device appears to understand */
-#define DSB100_TUNE 1
-#define DSB100_ONOFF 2
-
-#define TB_LEN 16
-
-/* Frequency limits in MHz -- these are European values.  For Japanese
-devices, that would be 76 and 91.  */
-#define FREQ_MIN  87.5
-#define FREQ_MAX 108.0
-#define FREQ_MUL 16000
-
-
-static int usb_dsbr100_probe(struct usb_interface *intf,
-                            const struct usb_device_id *id);
-static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg);
-static int usb_dsbr100_open(struct inode *inode, struct file *file);
-static int usb_dsbr100_close(struct inode *inode, struct file *file);
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-/* Data for one (physical) device */
-typedef struct {
-       struct usb_device *usbdev;
-       struct video_device *videodev;
-       unsigned char transfer_buffer[TB_LEN];
-       int curfreq;
-       int stereo;
-       int users;
-       int removed;
-} dsbr100_device;
-
-
-/* File system interface */
-static struct file_operations usb_dsbr100_fops = {
-       .owner =        THIS_MODULE,
-       .open =         usb_dsbr100_open,
-       .release =      usb_dsbr100_close,
-       .ioctl =        usb_dsbr100_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-
-/* V4L interface */
-static struct video_device dsbr100_videodev_template=
-{
-       .owner =        THIS_MODULE,
-       .name =         "D-Link DSB-R 100",
-       .type =         VID_TYPE_TUNER,
-       .hardware =     VID_HARDWARE_AZTECH,
-       .fops =         &usb_dsbr100_fops,
-       .release = video_device_release,
-};
-
-static struct usb_device_id usb_dsbr100_device_table [] = {
-       { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_dsbr100_driver = {
-       .name =         "dsbr100",
-       .probe =        usb_dsbr100_probe,
-       .disconnect =   usb_dsbr100_disconnect,
-       .id_table =     usb_dsbr100_device_table,
-};
-
-/* Low-level device interface begins here */
-
-/* switch on radio */
-static int dsbr100_start(dsbr100_device *radio)
-{
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_ONOFF, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
-               return -1;
-       return (radio->transfer_buffer)[0];
-}
-
-
-/* switch off radio */
-static int dsbr100_stop(dsbr100_device *radio)
-{
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_ONOFF, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
-               return -1;
-       return (radio->transfer_buffer)[0];
-}
-
-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(dsbr100_device *radio, int freq)
-{
-       freq = (freq/16*80)/1000+856;
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_TUNE, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       (freq>>8)&0x00ff, freq&0xff, 
-                       radio->transfer_buffer, 8, 300)<0 ||
-          usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
-                       0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
-               radio->stereo = -1;
-               return -1;
-       }
-       radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
-       return (radio->transfer_buffer)[0];
-}
-
-/* return the device status.  This is, in effect, just whether it
-sees a stereo signal or not.  Pity. */
-static void dsbr100_getstat(dsbr100_device *radio)
-{
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-               USB_REQ_GET_STATUS, 
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-               0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
-               radio->stereo = -1;
-       else
-               radio->stereo = ! (radio->transfer_buffer[0]&0x01);
-}
-
-
-/* USB subsystem interface begins here */
-
-/* check if the device is present and register with v4l and
-usb if it is */
-static int usb_dsbr100_probe(struct usb_interface *intf, 
-                        const struct usb_device_id *id)
-{
-       dsbr100_device *radio;
-
-       if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
-               return -ENOMEM;
-       if (!(radio->videodev = video_device_alloc())) {
-               kfree(radio);
-               return -ENOMEM;
-       }
-       memcpy(radio->videodev, &dsbr100_videodev_template, 
-               sizeof(dsbr100_videodev_template));
-       radio->removed = 0;
-       radio->users = 0;
-       radio->usbdev = interface_to_usbdev(intf);
-       radio->curfreq = FREQ_MIN*FREQ_MUL;
-       video_set_drvdata(radio->videodev, radio);
-       if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
-               radio_nr)) {
-               warn("Could not register video device");
-               video_device_release(radio->videodev);
-               kfree(radio);
-               return -EIO;
-       }
-       usb_set_intfdata(intf, radio);
-       return 0;
-}
-
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it.  If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it.  stv680.c does not relase its private
-data, so I don't do this here either.  Checking out the
-code I'd expect I better did that, but if there's a memory
-leak here it's tiny (~50 bytes per disconnect) */
-static void usb_dsbr100_disconnect(struct usb_interface *intf)
-{
-       dsbr100_device *radio = usb_get_intfdata(intf);
-
-       usb_set_intfdata (intf, NULL);
-       if (radio) {
-               video_unregister_device(radio->videodev);
-               radio->videodev = NULL;
-               if (radio->users) {
-                       kfree(radio);
-               } else {
-                       radio->removed = 1;
-               }
-       }
-}
-
-
-/* Video for Linux interface */
-
-static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
-                               unsigned int cmd, void *arg)
-{
-       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-       if (!radio)
-               return -EIO;
-
-       switch(cmd) {
-               case VIDIOCGCAP: {
-                       struct video_capability *v = arg;
-
-                       memset(v, 0, sizeof(*v));
-                       v->type = VID_TYPE_TUNER;
-                       v->channels = 1;
-                       v->audios = 1;
-                       strcpy(v->name, "D-Link R-100 USB FM Radio");
-                       return 0;
-               }
-               case VIDIOCGTUNER: {
-                       struct video_tuner *v = arg;
-
-                       dsbr100_getstat(radio);
-                       if(v->tuner)    /* Only 1 tuner */ 
-                               return -EINVAL;
-                       v->rangelow = FREQ_MIN*FREQ_MUL;
-                       v->rangehigh = FREQ_MAX*FREQ_MUL;
-                       v->flags = VIDEO_TUNER_LOW;
-                       v->mode = VIDEO_MODE_AUTO;
-                       v->signal = radio->stereo*0x7000;
-                               /* Don't know how to get signal strength */
-                       v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
-                       strcpy(v->name, "DSB R-100");
-                       return 0;
-               }
-               case VIDIOCSTUNER: {
-                       struct video_tuner *v = arg;
-
-                       if(v->tuner!=0)
-                               return -EINVAL;
-                       /* Only 1 tuner so no setting needed ! */
-                       return 0;
-               }
-               case VIDIOCGFREQ: {
-                       int *freq = arg;
-
-                       if (radio->curfreq==-1)
-                               return -EINVAL;
-                       *freq = radio->curfreq;
-                       return 0;
-               }
-               case VIDIOCSFREQ: {
-                       int *freq = arg;
-
-                       radio->curfreq = *freq;
-                       if (dsbr100_setfreq(radio, radio->curfreq)==-1)
-                               warn("Set frequency failed");
-                       return 0;
-               }
-               case VIDIOCGAUDIO: {
-                       struct video_audio *v = arg;
-
-                       memset(v, 0, sizeof(*v));
-                       v->flags |= VIDEO_AUDIO_MUTABLE;
-                       v->mode = VIDEO_SOUND_STEREO;
-                       v->volume = 1;
-                       v->step = 1;
-                       strcpy(v->name, "Radio");
-                       return 0;                       
-               }
-               case VIDIOCSAUDIO: {
-                       struct video_audio *v = arg;
-
-                       if (v->audio) 
-                               return -EINVAL;
-                       if (v->flags&VIDEO_AUDIO_MUTE) {
-                               if (dsbr100_stop(radio)==-1)
-                                       warn("Radio did not respond properly");
-                       }
-                       else
-                               if (dsbr100_start(radio)==-1)
-                                       warn("Radio did not respond properly");
-                       return 0;
-               }
-               default:
-                       return -ENOIOCTLCMD;
-       }
-}
-
-static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
-}
-
-static int usb_dsbr100_open(struct inode *inode, struct file *file)
-{
-       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-       radio->users = 1;
-       if (dsbr100_start(radio)<0) {
-               warn("Radio did not start up properly");
-               radio->users = 0;
-               return -EIO;
-       }
-       dsbr100_setfreq(radio, radio->curfreq);
-       return 0;
-}
-
-static int usb_dsbr100_close(struct inode *inode, struct file *file)
-{
-       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-       if (!radio)
-               return -ENODEV;
-       radio->users = 0;
-       if (radio->removed) {
-               kfree(radio);
-       }
-       return 0;
-}
-
-static int __init dsbr100_init(void)
-{
-       int retval = usb_register(&usb_dsbr100_driver);
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return retval;
-}
-
-static void __exit dsbr100_exit(void)
-{
-       usb_deregister(&usb_dsbr100_driver);
-}
-
-module_init (dsbr100_init);
-module_exit (dsbr100_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h
deleted file mode 100644 (file)
index eee8afc..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ET61X251_H_
-#define _ET61X251_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-
-#include "et61x251_sensor.h"
-
-/*****************************************************************************/
-
-#define ET61X251_DEBUG
-#define ET61X251_DEBUG_LEVEL         2
-#define ET61X251_MAX_DEVICES         64
-#define ET61X251_PRESERVE_IMGSCALE   0
-#define ET61X251_FORCE_MUNMAP        0
-#define ET61X251_MAX_FRAMES          32
-#define ET61X251_COMPRESSION_QUALITY 0
-#define ET61X251_URBS                2
-#define ET61X251_ISO_PACKETS         7
-#define ET61X251_ALTERNATE_SETTING   13
-#define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
-#define ET61X251_CTRL_TIMEOUT        100
-#define ET61X251_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-static const struct usb_device_id et61x251_id_table[] = {
-       { USB_DEVICE(0x102c, 0x6151), },
-       { USB_DEVICE(0x102c, 0x6251), },
-       { USB_DEVICE(0x102c, 0x6253), },
-       { USB_DEVICE(0x102c, 0x6254), },
-       { USB_DEVICE(0x102c, 0x6255), },
-       { USB_DEVICE(0x102c, 0x6256), },
-       { USB_DEVICE(0x102c, 0x6257), },
-       { USB_DEVICE(0x102c, 0x6258), },
-       { USB_DEVICE(0x102c, 0x6259), },
-       { USB_DEVICE(0x102c, 0x625a), },
-       { USB_DEVICE(0x102c, 0x625b), },
-       { USB_DEVICE(0x102c, 0x625c), },
-       { USB_DEVICE(0x102c, 0x625d), },
-       { USB_DEVICE(0x102c, 0x625e), },
-       { USB_DEVICE(0x102c, 0x625f), },
-       { USB_DEVICE(0x102c, 0x6260), },
-       { USB_DEVICE(0x102c, 0x6261), },
-       { USB_DEVICE(0x102c, 0x6262), },
-       { USB_DEVICE(0x102c, 0x6263), },
-       { USB_DEVICE(0x102c, 0x6264), },
-       { USB_DEVICE(0x102c, 0x6265), },
-       { USB_DEVICE(0x102c, 0x6266), },
-       { USB_DEVICE(0x102c, 0x6267), },
-       { USB_DEVICE(0x102c, 0x6268), },
-       { USB_DEVICE(0x102c, 0x6269), },
-       { }
-};
-
-ET61X251_SENSOR_TABLE
-
-/*****************************************************************************/
-
-enum et61x251_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct et61x251_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum et61x251_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum et61x251_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum et61x251_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum et61x251_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-struct et61x251_sysfs_attr {
-       u8 reg, i2c_reg;
-};
-
-struct et61x251_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
-
-struct et61x251_device {
-       struct video_device* v4ldev;
-
-       struct et61x251_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[ET61X251_URBS];
-       void* transfer_buffer[ET61X251_URBS];
-       u8* control_buffer;
-
-       struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum et61x251_io_method io;
-       enum et61x251_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct et61x251_sysfs_attr sysfs;
-       struct et61x251_module_param module_param;
-
-       enum et61x251_dev_state state;
-       u8 users;
-
-       struct mutex dev_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
-{
-       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
-               return cam;
-
-       return NULL;
-}
-
-
-void
-et61x251_attach_sensor(struct et61x251_device* cam,
-                       struct et61x251_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ET61X251_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("et61x251: " fmt "\n", ## args);              \
-               else if ((level) == 3)                                        \
-                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-         __FUNCTION__, __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ET61X251_H_ */
diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c
deleted file mode 100644 (file)
index 7cc01b8..0000000
+++ /dev/null
@@ -1,2630 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "et61x251.h"
-
-/*****************************************************************************/
-
-#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
-                                "PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
-#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.02"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, et61x251_id_table);
-
-MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
-MODULE_VERSION(ET61X251_MODULE_VERSION);
-MODULE_LICENSE(ET61X251_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "
-                 __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second registered camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-                               ET61X251_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-                                       ET61X251_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                 "\n<n[,...]> Timeout for a video frame in seconds."
-                 "\nThis parameter is specific for each detected camera."
-                 "\nDefault value is "
-                 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
-                 "\n");
-
-#ifdef ET61X251_DEBUG
-static unsigned short debug = ET61X251_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
-                 "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-et61x251_request_buffers(struct et61x251_device* cam, u32 count,
-                         enum et61x251_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > ET61X251_MAX_FRAMES)
-               count = ET61X251_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void et61x251_release_buffers(struct et61x251_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void et61x251_empty_framequeues(struct et61x251_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void et61x251_requeue_outqueue(struct et61x251_device* cam)
-{
-       struct et61x251_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void et61x251_queue_unusedframes(struct et61x251_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       *buff = value;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (value 0x%02X, index "
-                      "0x%02X, error %d)", value, index, res);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-int et61x251_read_reg(struct et61x251_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-                   index, res);
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
-{
-       int i, r;
-
-       for (i = 1; i <= 8; i++) {
-               if (sensor->interface == ET61X251_I2C_3WIRES) {
-                       r = et61x251_read_reg(cam, 0x8e);
-                       if (!(r & 0x02) && (r >= 0))
-                               return 0;
-               } else {
-                       r = et61x251_read_reg(cam, 0x8b);
-                       if (!(r & 0x01) && (r >= 0))
-                               return 0;
-               }
-               if (r < 0)
-                       return -EIO;
-               udelay(8*8); /* minimum for sensors at 400kHz */
-       }
-
-       return -EBUSY;
-}
-
-
-int
-et61x251_i2c_try_read(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor, u8 address)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x10;
-       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, sensor);
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       if (err)
-               DBG(3, "I2C read failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-
-       return err ? -1 : (int)data[0];
-}
-
-
-int
-et61x251_i2c_try_write(struct et61x251_device* cam,
-                       struct et61x251_sensor* sensor, u8 address, u8 value)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x12;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       data[0] = value;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, sensor);
-
-       if (err)
-               DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-
-       return err ? -1 : 0;
-}
-
-
-int
-et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
-                       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
-                       u8 data8, u8 address)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = data2;
-       data[1] = data3;
-       data[2] = data4;
-       data[3] = data5;
-       data[4] = data6;
-       data[5] = data7;
-       data[6] = data8;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x02 | (n << 4);
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       /* Start writing through the serial interface */
-       data[0] = data1;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, &cam->sensor);
-
-       if (err)
-               DBG(3, "I2C raw write failed for %s image sensor",
-                   cam->sensor.name);
-
-       PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
-             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
-             " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
-             data1, data2, data3, data4, data5, data6, data7, data8);
-
-       return err ? -1 : 0;
-
-}
-
-
-int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-{
-       return et61x251_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
-{
-       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-/*****************************************************************************/
-
-static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
-{
-       struct et61x251_device* cam = urb->context;
-       struct et61x251_frame_t** f;
-       size_t imagesize;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int len, status;
-               void *pos;
-               u8* b1, * b2, sof;
-               const u8 VOID_BYTES = 6;
-               size_t imglen;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               b1 = pos++;
-               b2 = pos++;
-               sof = ((*b1 & 0x3f) == 63);
-               imglen = ((*b1 & 0xc0) << 2) | *b2;
-
-               PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
-                     len, i, imglen);
-
-               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-                       if (sof) {
-                               (*f)->state = F_GRABBING;
-                               (*f)->buf.bytesused = 0;
-                               do_gettimeofday(&(*f)->buf.timestamp);
-                               pos += 22;
-                               DBG(3, "SOF detected: new video frame");
-                       }
-
-               if ((*f)->state == F_GRABBING) {
-                       if (sof && (*f)->buf.bytesused) {
-                               if (cam->sensor.pix_format.pixelformat ==
-                                                        V4L2_PIX_FMT_ET61X251)
-                                       goto end_of_frame;
-                               else {
-                                       DBG(3, "Not expected SOF detected "
-                                              "after %lu bytes",
-                                          (unsigned long)(*f)->buf.bytesused);
-                                       (*f)->state = F_ERROR;
-                                       continue;
-                               }
-                       }
-
-                       if ((*f)->buf.bytesused + imglen > imagesize) {
-                               DBG(3, "Video frame size exceeded");
-                               (*f)->state = F_ERROR;
-                               continue;
-                       }
-
-                       pos += VOID_BYTES;
-
-                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
-                       (*f)->buf.bytesused += imglen;
-
-                       if ((*f)->buf.bytesused == imagesize) {
-                               u32 b;
-end_of_frame:
-                               b = (*f)->buf.bytesused;
-                               (*f)->state = F_DONE;
-                               (*f)->buf.sequence= ++cam->frame_count;
-                               spin_lock(&cam->queue_lock);
-                               list_move_tail(&(*f)->frame, &cam->outqueue);
-                               if (!list_empty(&cam->inqueue))
-                                       (*f) = list_entry(cam->inqueue.next,
-                                                      struct et61x251_frame_t,
-                                                         frame);
-                               else
-                                       (*f) = NULL;
-                               spin_unlock(&cam->queue_lock);
-                               DBG(3, "Video frame captured: : %lu bytes",
-                                      (unsigned long)(b));
-
-                               if (!(*f))
-                                       goto resubmit_urb;
-
-                               if (sof &&
-                                   cam->sensor.pix_format.pixelformat ==
-                                                        V4L2_PIX_FMT_ET61X251)
-                                       goto start_of_frame;
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int et61x251_start_transfer(struct et61x251_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
-                                              864, 896, 920, 956, 980, 1000,
-                                              1022};
-       const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < ET61X251_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < ET61X251_URBS; i++) {
-               urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = ET61X251_ISO_PACKETS;
-               urb->complete = et61x251_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       err = et61x251_write_reg(cam, 0x01, 0x03);
-       err = et61x251_write_reg(cam, 0x00, 0x03);
-       err = et61x251_write_reg(cam, 0x08, 0x03);
-       if (err) {
-               err = -EIO;
-               DBG(1, "I/O hardware error");
-               goto free_urbs;
-       }
-
-       err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < ET61X251_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int et61x251_stop_transfer(struct et61x251_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = ET61X251_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int et61x251_stream_interrupt(struct et61x251_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    ET61X251_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. To "
-                      "use it, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
-{
-       char str[5];
-       char* endp;
-       unsigned long val;
-
-       if (len < 4) {
-               strncpy(str, buff, len);
-               str[len+1] = '\0';
-       } else {
-               strncpy(str, buff, 4);
-               str[4] = '\0';
-       }
-
-       val = simple_strtoul(str, &endp, 0);
-
-       *count = 0;
-       if (val <= 0xff)
-               *count = (ssize_t)(endp - str);
-       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
-               *count += 1;
-
-       return (u8)val;
-}
-
-/*
-   NOTE 1: being inside one of the following methods implies that the v4l
-           device exists for sure (see kobjects and reference counters)
-   NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = et61x251_strtou8(buf, len, &count);
-       if (index > 0x8e || !count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.reg = index;
-
-       DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       value = et61x251_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = et61x251_write_reg(cam, value, cam->sysfs.reg);
-       if (err) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = et61x251_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.i2c_reg = index;
-
-       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       value = et61x251_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
-       if (err) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.i2c_reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-                         et61x251_show_reg, et61x251_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-                         et61x251_show_val, et61x251_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-                         et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-                         et61x251_show_i2c_val, et61x251_store_i2c_val);
-
-
-static void et61x251_create_sysfs(struct et61x251_device* cam)
-{
-       struct video_device *v4ldev = cam->v4ldev;
-
-       video_device_create_file(v4ldev, &class_device_attr_reg);
-       video_device_create_file(v4ldev, &class_device_attr_val);
-       if (cam->sensor.sysfs_ops) {
-               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
-       }
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-et61x251_set_pix_format(struct et61x251_device* cam,
-                        struct v4l2_pix_format* pix)
-{
-       int r, err = 0;
-
-       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
-               err += r;
-       if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
-               err += et61x251_write_reg(cam, r & 0xfd, 0x12);
-       else
-               err += et61x251_write_reg(cam, r | 0x02, 0x12);
-
-       return err ? -EIO : 0;
-}
-
-
-static int
-et61x251_set_compression(struct et61x251_device* cam,
-                         struct v4l2_jpegcompression* compression)
-{
-       int r, err = 0;
-
-       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
-               err += r;
-       if (compression->quality == 0)
-               err += et61x251_write_reg(cam, r & 0xfb, 0x12);
-       else
-               err += et61x251_write_reg(cam, r | 0x04, 0x12);
-
-       return err ? -EIO : 0;
-}
-
-
-static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
-{
-       int r = 0, err = 0;
-
-       r = et61x251_read_reg(cam, 0x12);
-       if (r < 0)
-               err += r;
-
-       if (scale == 1)
-               err += et61x251_write_reg(cam, r & ~0x01, 0x12);
-       else if (scale == 2)
-               err += et61x251_write_reg(cam, r | 0x01, 0x12);
-
-       if (err)
-               return -EIO;
-
-       PDBGG("Scaling factor: %u", scale);
-
-       return 0;
-}
-
-
-static int
-et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
-                          s->active_pixel.left),
-           fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
-                          s->active_pixel.top),
-           fmw_length = (u16)(rect->width),
-           fmw_height = (u16)(rect->height);
-       int err = 0;
-
-       err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
-       err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
-       err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
-       err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
-       err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
-                                      | ((fmw_length & 0x300) >> 4)
-                                      | ((fmw_height & 0x300) >> 2), 0x6d);
-       if (err)
-               return -EIO;
-
-       PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
-             fmw_sx, fmw_sy, fmw_length, fmw_height);
-
-       return 0;
-}
-
-
-static int et61x251_init(struct et61x251_device* cam)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-               cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
-       err += et61x251_set_crop(cam, rect);
-       if (err)
-               return err;
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       err += et61x251_set_compression(cam, &cam->compression);
-       err += et61x251_set_pix_format(cam, &s->pix_format);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, &s->pix_format);
-       if (err)
-               return err;
-
-       if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
-               DBG(3, "Compressed video format is active, quality %d",
-                   cam->compression.quality);
-       else
-               DBG(3, "Uncompressed video format is active");
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-
-static void et61x251_release_resources(struct et61x251_device* cam)
-{
-       mutex_lock(&et61x251_sysfs_lock);
-
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-
-       usb_put_dev(cam->usbdev);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       kfree(cam->control_buffer);
-}
-
-/*****************************************************************************/
-
-static int et61x251_open(struct inode* inode, struct file* filp)
-{
-       struct et61x251_device* cam;
-       int err = 0;
-
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&et61x251_disconnect))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&et61x251_disconnect);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
-               if (err) {
-                       up_read(&et61x251_disconnect);
-                       return err;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&et61x251_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = et61x251_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = et61x251_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       et61x251_empty_framequeues(cam);
-
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
-
-out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&et61x251_disconnect);
-       return err;
-}
-
-
-static int et61x251_release(struct inode* inode, struct file* filp)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       et61x251_stop_transfer(cam);
-
-       et61x251_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               et61x251_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-}
-
-
-static ssize_t
-et61x251_read(struct file* filp, char __user * buf,
-              size_t count, loff_t* f_pos)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       struct et61x251_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose the read "
-                      "method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
-                                             IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       et61x251_empty_framequeues(cam);
-               et61x251_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       et61x251_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err ? err : count;
-}
-
-
-static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       struct et61x251_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
-                                             IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               et61x251_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void et61x251_vm_open(struct vm_area_struct* vma)
-{
-       struct et61x251_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void et61x251_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct et61x251_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static struct vm_operations_struct et61x251_vm_ops = {
-       .open = et61x251_vm_open,
-       .close = et61x251_vm_close,
-};
-
-
-static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &et61x251_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-
-       et61x251_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "et61x251",
-               .version = ET61X251_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_pix_format* pix_format = &(s->pix_format);
-       u8 scale;
-       const enum et61x251_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       /* Preserve R,G or B origin */
-       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
-       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
-       if (rect->width < 4)
-               rect->width = 4;
-       if (rect->height < 4)
-               rect->height = 4;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-
-       rect->width &= ~3L;
-       rect->height &= ~3L;
-
-       if (ET61X251_PRESERVE_IMGSCALE) {
-               /* Calculate the actual scaling factor */
-               u32 a, b;
-               a = rect->width * rect->height;
-               b = pix_format->width * pix_format->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-       } else
-               scale = 1;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               et61x251_release_buffers(cam);
-
-       err = et61x251_set_crop(cam, rect);
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-       err += et61x251_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width/scale;
-       s->pix_format.height = rect->height/scale;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               et61x251_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               et61x251_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "bayer rgb");
-               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-       } else if (fmtd.index == 1) {
-               strcpy(fmtd.description, "compressed");
-               fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
-                            ? 0 : (pfmt->width * pfmt->priv) / 8;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
-                          void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       u8 scale;
-       const enum et61x251_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       { /* calculate the actual scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-       }
-
-       rect.width = scale * pix->width;
-       rect.height = scale * pix->height;
-
-       if (rect.width < 4)
-               rect.width = 4;
-       if (rect.height < 4)
-               rect.height = 4;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-
-       rect.width &= ~3L;
-       rect.height &= ~3L;
-
-       { /* adjust the scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-       }
-
-       pix->width = rect.width / scale;
-       pix->height = rect.height / scale;
-
-       if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
-           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-               pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv; /* bpp */
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
-                           ? 0 : (pix->width * pix->priv) / 8;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               et61x251_release_buffers(cam);
-
-       err += et61x251_set_pix_format(cam, pix);
-       err += et61x251_set_crop(cam, &rect);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, pix);
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-       err += et61x251_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               et61x251_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               et61x251_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression,
-                        sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum et61x251_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0 && jc.quality != 1)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       err += et61x251_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open "
-                      "/dev/video%d again.", cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. "
-                              "Previous buffers are still mapped.");
-                       return -EINVAL;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       et61x251_empty_framequeues(cam);
-
-       et61x251_release_buffers(cam);
-       if (rb.count)
-               rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               et61x251_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
-                      void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct et61x251_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       et61x251_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
-               sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
-                               unsigned int cmd, void __user * arg)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return et61x251_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return et61x251_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return et61x251_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return et61x251_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return et61x251_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return et61x251_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-               return et61x251_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP_OLD:
-       case VIDIOC_CROPCAP:
-               return et61x251_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return et61x251_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return et61x251_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return et61x251_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return et61x251_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return et61x251_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return et61x251_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return et61x251_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return et61x251_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return et61x251_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return et61x251_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return et61x251_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return et61x251_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return et61x251_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-               return et61x251_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static int et61x251_ioctl(struct inode* inode, struct file* filp,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "et61x251", cmd);
-
-       err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-
-static struct file_operations et61x251_fops = {
-       .owner = THIS_MODULE,
-       .open =    et61x251_open,
-       .release = et61x251_release,
-       .ioctl =   et61x251_ioctl,
-       .read =    et61x251_read,
-       .poll =    et61x251_poll,
-       .mmap =    et61x251_mmap,
-       .llseek =  no_llseek,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct et61x251_device* cam;
-       static unsigned int dev_nr = 0;
-       unsigned int i;
-       int err = 0;
-
-       if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       mutex_init(&cam->dev_mutex);
-
-       DBG(2, "ET61X[12]51 PC Camera Controller detected "
-              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
-
-       for  (i = 0; et61x251_sensor_table[i]; i++) {
-               err = et61x251_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err)
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-       else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (et61x251_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
-       cam->v4ldev->fops = &et61x251_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       mutex_lock(&cam->dev_mutex);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       et61x251_create_sysfs(cam);
-       DBG(2, "Optional device control through 'sysfs' interface ready");
-#endif
-
-       usb_set_intfdata(intf, cam);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void et61x251_usb_disconnect(struct usb_interface* intf)
-{
-       struct et61x251_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
-
-       down_write(&et61x251_disconnect);
-
-       mutex_lock(&cam->dev_mutex);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       wake_up_interruptible_all(&cam->open);
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor);
-               cam->state |= DEV_MISCONFIGURED;
-               et61x251_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
-               cam->state |= DEV_DISCONNECTED;
-               et61x251_release_resources(cam);
-       }
-
-       mutex_unlock(&cam->dev_mutex);
-
-       if (!cam->users)
-               kfree(cam);
-
-       up_write(&et61x251_disconnect);
-}
-
-
-static struct usb_driver et61x251_usb_driver = {
-       .name =       "et61x251",
-       .id_table =   et61x251_id_table,
-       .probe =      et61x251_usb_probe,
-       .disconnect = et61x251_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init et61x251_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION);
-       KDBG(3, ET61X251_MODULE_AUTHOR);
-
-       if ((err = usb_register(&et61x251_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit et61x251_module_exit(void)
-{
-       usb_deregister(&et61x251_usb_driver);
-}
-
-
-module_init(et61x251_module_init);
-module_exit(et61x251_module_exit);
diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h
deleted file mode 100644 (file)
index 56841ae..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ET61X251_SENSOR_H_
-#define _ET61X251_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct et61x251_device;
-struct et61x251_sensor;
-
-/*****************************************************************************/
-
-extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
-
-#define ET61X251_SENSOR_TABLE                                                 \
-/* Weak detections must go at the end of the list */                          \
-static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
-       &et61x251_probe_tas5130d1b,                                           \
-       NULL,                                                                 \
-};
-
-extern struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
-
-extern void
-et61x251_attach_sensor(struct et61x251_device* cam,
-                       struct et61x251_sensor* sensor);
-
-/*****************************************************************************/
-
-extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
-extern int et61x251_read_reg(struct et61x251_device*, u16 index);
-extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
-extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
-extern int et61x251_i2c_try_write(struct et61x251_device*,
-                                  struct et61x251_sensor*, u8 address,
-                                  u8 value);
-extern int et61x251_i2c_try_read(struct et61x251_device*,
-                                 struct et61x251_sensor*, u8 address);
-extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
-                                  u8 data2, u8 data3, u8 data4, u8 data5,
-                                  u8 data6, u8 data7, u8 data8, u8 address);
-
-/*****************************************************************************/
-
-enum et61x251_i2c_sysfs_ops {
-       ET61X251_I2C_READ = 0x01,
-       ET61X251_I2C_WRITE = 0x02,
-};
-
-enum et61x251_i2c_interface {
-       ET61X251_I2C_2WIRES,
-       ET61X251_I2C_3WIRES,
-};
-
-/* Repeat start condition when RSTA is high */
-enum et61x251_i2c_rsta {
-       ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
-       ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
-};
-
-#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-
-struct et61x251_sensor {
-       char name[32];
-
-       enum et61x251_i2c_sysfs_ops sysfs_ops;
-
-       enum et61x251_i2c_interface interface;
-       u8 i2c_slave_id;
-       enum et61x251_i2c_rsta rsta;
-       struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
-
-       struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
-       struct v4l2_cropcap cropcap;
-       struct v4l2_pix_format pix_format;
-
-       int (*init)(struct et61x251_device* cam);
-       int (*get_ctrl)(struct et61x251_device* cam,
-                       struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct et61x251_device* cam,
-                       const struct v4l2_control* ctrl);
-       int (*set_crop)(struct et61x251_device* cam,
-                       const struct v4l2_rect* rect);
-       int (*set_pix_format)(struct et61x251_device* cam,
-                             const struct v4l2_pix_format* pix);
-
-       /* Private */
-       struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c
deleted file mode 100644 (file)
index 3998d76..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
- * PC Camera Controllers                                                   *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "et61x251_sensor.h"
-
-
-static int tas5130d1b_init(struct et61x251_device* cam)
-{
-       int err = 0;
-
-       err += et61x251_write_reg(cam, 0x14, 0x01);
-       err += et61x251_write_reg(cam, 0x1b, 0x02);
-       err += et61x251_write_reg(cam, 0x02, 0x12);
-       err += et61x251_write_reg(cam, 0x0e, 0x60);
-       err += et61x251_write_reg(cam, 0x80, 0x61);
-       err += et61x251_write_reg(cam, 0xf0, 0x62);
-       err += et61x251_write_reg(cam, 0x03, 0x63);
-       err += et61x251_write_reg(cam, 0x14, 0x64);
-       err += et61x251_write_reg(cam, 0xf4, 0x65);
-       err += et61x251_write_reg(cam, 0x01, 0x66);
-       err += et61x251_write_reg(cam, 0x05, 0x67);
-       err += et61x251_write_reg(cam, 0x8f, 0x68);
-       err += et61x251_write_reg(cam, 0x0f, 0x8d);
-       err += et61x251_write_reg(cam, 0x08, 0x8e);
-
-       return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
-                               const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               err += et61x251_i2c_raw_write(cam, 2, 0x20,
-                                             0xf6-ctrl->value, 0, 0, 0,
-                                             0, 0, 0, 0);
-               break;
-       case V4L2_CID_EXPOSURE:
-               err += et61x251_i2c_raw_write(cam, 2, 0x40,
-                                             0x47-ctrl->value, 0, 0, 0,
-                                             0, 0, 0, 0);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static struct et61x251_sensor tas5130d1b = {
-       .name = "TAS5130D1B",
-       .interface = ET61X251_I2C_3WIRES,
-       .rsta = ET61X251_I2C_RSTA_STOP,
-       .active_pixel = {
-               .left = 106,
-               .top = 13,
-       },
-       .init = &tas5130d1b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0xf6,
-                       .step = 0x02,
-                       .default_value = 0x0d,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = 0x47,
-                       .step = 0x01,
-                       .default_value = 0x23,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &tas5130d1b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-};
-
-
-int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
-{
-       const struct usb_device_id tas5130d1b_id_table[] = {
-               { USB_DEVICE(0x102c, 0x6251), },
-               { }
-       };
-
-       /* Sensor detection is based on USB pid/vid */
-       if (!et61x251_match_id(cam, tas5130d1b_id_table))
-               return -ENODEV;
-
-       et61x251_attach_sensor(cam, &tas5130d1b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
deleted file mode 100644 (file)
index a42c222..0000000
+++ /dev/null
@@ -1,3932 +0,0 @@
-/*
- * USB IBM C-It Video Camera driver
- *
- * Supports Xirlink C-It Video Camera, IBM PC Camera,
- * IBM NetCamera and Veo Stingray.
- *
- * This driver is based on earlier work of:
- *
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- *
- * 5/24/00 Removed optional (and unnecessary) locking of the driver while
- * the device remains plugged in. Corrected race conditions in ibmcam_open
- * and ibmcam_probe() routines using this as a guideline:
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define IBMCAM_VENDOR_ID       0x0545
-#define IBMCAM_PRODUCT_ID      0x8080
-#define NETCAM_PRODUCT_ID      0x8002  /* IBM NetCamera, close to model 2 */
-#define VEO_800C_PRODUCT_ID    0x800C  /* Veo Stingray, repackaged Model 2 */
-#define VEO_800D_PRODUCT_ID    0x800D  /* Veo Stingray, repackaged Model 4 */
-
-#define MAX_IBMCAM             4       /* How many devices we allow to connect */
-#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
-
-/* Header signatures */
-
-/* Model 1 header: 00 FF 00 xx */
-#define HDRSIG_MODEL1_128x96   0x06    /* U Y V Y ... */
-#define HDRSIG_MODEL1_176x144  0x0e    /* U Y V Y ... */
-#define HDRSIG_MODEL1_352x288  0x00    /* V Y U Y ... */
-
-#define        IBMCAM_MODEL_1  1       /* XVP-501, 3 interfaces, rev. 0.02 */
-#define IBMCAM_MODEL_2 2       /* KSX-X9903, 2 interfaces, rev. 3.0a */
-#define IBMCAM_MODEL_3 3       /* KSX-X9902, 2 interfaces, rev. 3.01 */
-#define        IBMCAM_MODEL_4  4       /* IBM NetCamera, 0545/8002/3.0a */
-
-/* Video sizes supported */
-#define        VIDEOSIZE_128x96        VIDEOSIZE(128, 96)
-#define        VIDEOSIZE_176x144       VIDEOSIZE(176,144)
-#define        VIDEOSIZE_352x288       VIDEOSIZE(352,288)
-#define        VIDEOSIZE_320x240       VIDEOSIZE(320,240)
-#define        VIDEOSIZE_352x240       VIDEOSIZE(352,240)
-#define        VIDEOSIZE_640x480       VIDEOSIZE(640,480)
-#define        VIDEOSIZE_160x120       VIDEOSIZE(160,120)
-
-/* Video sizes supported */
-enum {
-       SIZE_128x96 = 0,
-       SIZE_160x120,
-       SIZE_176x144,
-       SIZE_320x240,
-       SIZE_352x240,
-       SIZE_352x288,
-       SIZE_640x480,
-       /* Add/remove/rearrange items before this line */
-       SIZE_LastItem
-};
-
-/*
- * This structure lives in uvd->user field.
- */
-typedef struct {
-       int initialized;        /* Had we already sent init sequence? */
-       int camera_model;       /* What type of IBM camera we got? */
-       int has_hdr;
-} ibmcam_t;
-#define        IBMCAM_T(uvd)   ((ibmcam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams;
-
-static int debug;
-
-static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth  = 8;
-static const int min_canvasHeight = 4;
-
-static int lighting = 1; /* Medium */
-
-#define SHARPNESS_MIN  0
-#define SHARPNESS_MAX  6
-static int sharpness = 4; /* Low noise, good details */
-
-#define FRAMERATE_MIN  0
-#define FRAMERATE_MAX  6
-static int framerate = -1;
-
-static int size = SIZE_352x288;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-/* Settings for camera model 2 */
-static int init_model2_rg2 = -1;
-static int init_model2_sat = -1;
-static int init_model2_yb = -1;
-
-/* 01.01.08 - Added for RCA video in support -LO */
-/* Settings for camera model 3 */
-static int init_model3_input = 0;
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-module_param(lighting, int, 0);
-MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480  (default=5)");
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-module_param(init_model2_rg2, int, 0);
-MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
-module_param(init_model2_sat, int, 0);
-MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
-module_param(init_model2_yb, int, 0);
-MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
-
-/* 01.01.08 - Added for RCA video in support -LO */
-module_param(init_model3_input, int, 0);
-MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
-
-MODULE_AUTHOR ("Dmitri");
-MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
-MODULE_LICENSE("GPL");
-
-/* Still mysterious i2c commands */
-static const unsigned short unknown_88 = 0x0088;
-static const unsigned short unknown_89 = 0x0089;
-static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
-static const unsigned short contrast_14 = 0x0014;
-static const unsigned short light_27 = 0x0027;
-static const unsigned short sharp_13 = 0x0013;
-
-/* i2c commands for Model 2 cameras */
-static const unsigned short mod2_brightness = 0x001a;          /* $5b .. $ee; default=$5a */
-static const unsigned short mod2_set_framerate = 0x001c;       /* 0 (fast).. $1F (slow) */
-static const unsigned short mod2_color_balance_rg2 = 0x001e;   /* 0 (red) .. $7F (green) */
-static const unsigned short mod2_saturation = 0x0020;          /* 0 (b/w) - $7F (full color) */
-static const unsigned short mod2_color_balance_yb = 0x0022;    /* 0..$7F, $50 is about right */
-static const unsigned short mod2_hue = 0x0024;                 /* 0..$7F, $70 is about right */
-static const unsigned short mod2_sensitivity = 0x0028;         /* 0 (min) .. $1F (max) */
-
-struct struct_initData {
-       unsigned char req;
-       unsigned short value;
-       unsigned short index;
-};
-
-/*
- * ibmcam_size_to_videosize()
- *
- * This procedure converts module option 'size' into the actual
- * videosize_t that defines the image size in pixels. We need
- * simplified 'size' because user wants a simple enumerated list
- * of choices, not an infinite set of possibilities.
- */
-static videosize_t ibmcam_size_to_videosize(int size)
-{
-       videosize_t vs = VIDEOSIZE_352x288;
-       RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
-       switch (size) {
-       case SIZE_128x96:
-               vs = VIDEOSIZE_128x96;
-               break;
-       case SIZE_160x120:
-               vs = VIDEOSIZE_160x120;
-               break;
-       case SIZE_176x144:
-               vs = VIDEOSIZE_176x144;
-               break;
-       case SIZE_320x240:
-               vs = VIDEOSIZE_320x240;
-               break;
-       case SIZE_352x240:
-               vs = VIDEOSIZE_352x240;
-               break;
-       case SIZE_352x288:
-               vs = VIDEOSIZE_352x288;
-               break;
-       case SIZE_640x480:
-               vs = VIDEOSIZE_640x480;
-               break;
-       default:
-               err("size=%d. is not valid", size);
-               break;
-       }
-       return vs;
-}
-
-/*
- * ibmcam_find_header()
- *
- * Locate one of supported header markers in the queue.
- * Once found, remove all preceding bytes AND the marker (4 bytes)
- * from the data pump queue. Whatever follows must be video lines.
- *
- * History:
- * 1/21/00  Created.
- */
-static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
-{
-       struct usbvideo_frame *frame;
-       ibmcam_t *icam;
-
-       if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-               err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
-               return scan_EndParse;
-       }
-       icam = IBMCAM_T(uvd);
-       assert(icam != NULL);
-       frame = &uvd->frame[uvd->curframe];
-       icam->has_hdr = 0;
-       switch (icam->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               const int marker_len = 4;
-               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
-                       {
-#if 0                          /* This code helps to detect new frame markers */
-                               info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
-#endif
-                               frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
-                               if ((frame->header == HDRSIG_MODEL1_128x96) ||
-                                   (frame->header == HDRSIG_MODEL1_176x144) ||
-                                   (frame->header == HDRSIG_MODEL1_352x288))
-                               {
-#if 0
-                                       info("Header found.");
-#endif
-                                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
-                                       icam->has_hdr = 1;
-                                       break;
-                               }
-                       }
-                       /* If we are still here then this doesn't look like a header */
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
-       {
-               int marker_len = 0;
-               switch (uvd->videosize) {
-               case VIDEOSIZE_176x144:
-                       marker_len = 10;
-                       break;
-               default:
-                       marker_len = 2;
-                       break;
-               }
-               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
-                       {
-#if 0
-                               info("Header found.");
-#endif
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
-                               icam->has_hdr = 1;
-                               frame->header = HDRSIG_MODEL1_176x144;
-                               break;
-                       }
-                       /* If we are still here then this doesn't look like a header */
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_3:
-       {       /*
-                * Headers: (one precedes every frame). nc=no compression,
-                * bq=best quality bf=best frame rate.
-                *
-                * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
-                * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
-                * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
-                *
-                * Bytes '00 FF' seem to indicate header. Other two bytes
-                * encode the frame type. This is a set of bit fields that
-                * encode image size, compression type etc. These fields
-                * do NOT contain frame number because all frames carry
-                * the same header.
-                */
-               const int marker_len = 4;
-               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
-                       {
-                               /*
-                                * Combine 2 bytes of frame type into one
-                                * easy to use value
-                                */
-                               unsigned long byte3, byte4;
-
-                               byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
-                               byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
-                               frame->header = (byte3 << 8) | byte4;
-#if 0
-                               info("Header found.");
-#endif
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
-                               icam->has_hdr = 1;
-                               break;
-                       }
-                       /* If we are still here then this doesn't look like a header */
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       if (!icam->has_hdr) {
-               if (uvd->debug > 2)
-                       info("Skipping frame, no header");
-               return scan_EndParse;
-       }
-
-       /* Header found */
-       icam->has_hdr = 1;
-       uvd->stats.header_count++;
-       frame->scanstate = ScanState_Lines;
-       frame->curline = 0;
-
-       if (flags & FLAGS_FORCE_TESTPATTERN) {
-               usbvideo_TestPattern(uvd, 1, 1);
-               return scan_NextFrame;
-       }
-       return scan_Continue;
-}
-
-/*
- * ibmcam_parse_lines()
- *
- * Parse one line (interlaced) from the buffer, put
- * decoded RGB value into the current frame buffer
- * and add the written number of bytes (RGB) to
- * the *pcopylen.
- *
- * History:
- * 21-Jan-2000 Created.
- * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
- */
-static enum ParseState ibmcam_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       unsigned char *f;
-       ibmcam_t *icam;
-       unsigned int len, scanLength, scanHeight, order_uv, order_yc;
-       int v4l_linesize; /* V4L line offset */
-       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
-       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
-       const int ccm = 128; /* Color correction median - see below */
-       int y, u, v, i, frame_done=0, color_corr;
-       static unsigned char lineBuffer[640*3];
-       unsigned const char *chromaLine, *lumaLine;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-       icam = IBMCAM_T(uvd);
-       assert(icam != NULL);
-       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
-               /* Model 4 frame markers do not carry image size identification */
-               switch (uvd->videosize) {
-               case VIDEOSIZE_128x96:
-               case VIDEOSIZE_160x120:
-               case VIDEOSIZE_176x144:
-                       scanLength = VIDEOSIZE_X(uvd->videosize);
-                       scanHeight = VIDEOSIZE_Y(uvd->videosize);
-                       break;
-               default:
-                       err("ibmcam_parse_lines: Wrong mode.");
-                       return scan_Out;
-               }
-               order_yc = 1;   /* order_yc: true=Yc false=cY ('c'=either U or V) */
-               order_uv = 1;   /* Always true in this algorithm */
-       } else {
-               switch (frame->header) {
-               case HDRSIG_MODEL1_128x96:
-                       scanLength = 128;
-                       scanHeight = 96;
-                       order_uv = 1;   /* U Y V Y ... */
-                       break;
-               case HDRSIG_MODEL1_176x144:
-                       scanLength = 176;
-                       scanHeight = 144;
-                       order_uv = 1;   /* U Y V Y ... */
-                       break;
-               case HDRSIG_MODEL1_352x288:
-                       scanLength = 352;
-                       scanHeight = 288;
-                       order_uv = 0;   /* Y V Y V ... */
-                       break;
-               default:
-                       err("Unknown header signature 00 FF 00 %02lX", frame->header);
-                       return scan_NextFrame;
-               }
-               /* order_yc: true=Yc false=cY ('c'=either U or V) */
-               order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
-       }
-
-       len = scanLength * 3;
-       assert(len <= sizeof(lineBuffer));
-
-       /*
-        * Lines are organized this way:
-        *
-        * I420:
-        * ~~~~
-        * <scanLength->
-        * ___________________________________
-        * |-----Y-----|---UVUVUV...UVUV-----| \
-        * |-----------+---------------------|  \
-        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. lines (interlaced)
-        * |...    ... |        ...          |  /
-        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. lines (interlaced)
-        * |___________|_____________________| /
-        *  \           \
-        *   lumaLine    chromaLine
-        */
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Mind that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
-               return scan_NextFrame;
-
-       /*
-        * Now we are sure that entire line (representing all 'scanLength'
-        * pixels from the camera) is available in the buffer. We
-        * start copying the line left-aligned to the V4L buffer.
-        * If the camera line is shorter then we should pad the V4L
-        * buffer with something (black) to complete the line.
-        */
-       assert(frame->data != NULL);
-       f = frame->data + (v4l_linesize * frame->curline);
-
-       /*
-        * To obtain chrominance data from the 'chromaLine' use this:
-        *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
-        *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
-        *
-        * Indices must be calculated this way:
-        * v_index = (i >> 1) << 2;
-        * u_index = (i >> 1) << 2 + 2;
-        *
-        * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
-        */
-       lumaLine = lineBuffer;
-       chromaLine = lineBuffer + scanLength;
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
-       {
-               unsigned char rv, gv, bv;       /* RGB components */
-
-               /* Check for various visual debugging hints (colorized pixels) */
-               if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
-                       /*
-                        * This is bad and should not happen. This means that
-                        * we somehow overshoot the line and encountered new
-                        * frame! Obviously our camera/V4L frame size is out
-                        * of whack. This cyan dot will help you to figure
-                        * out where exactly the new frame arrived.
-                        */
-                       if (icam->has_hdr == 1) {
-                               bv = 0; /* Yellow marker */
-                               gv = 0xFF;
-                               rv = 0xFF;
-                       } else {
-                               bv = 0xFF; /* Cyan marker */
-                               gv = 0xFF;
-                               rv = 0;
-                       }
-                       icam->has_hdr = 0;
-                       goto make_pixel;
-               }
-
-               /*
-                * Check if we are still in range. We may be out of range if our
-                * V4L canvas is wider or taller than the camera "native" image.
-                * Then we quickly fill the remainder of the line with zeros to
-                * make black color and quit the horizontal scanning loop.
-                */
-               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
-                       const int j = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
-                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
-                       f = frame->data + (v4l_linesize * frame->curline) + j;
-#endif
-                       memset(f, 0, v4l_linesize - j);
-                       break;
-               }
-
-               y = lumaLine[i];
-               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
-                       rv = gv = bv = y;
-               else {
-                       int off_0, off_2;
-
-                       off_0 = (i >> 1) << 2;
-                       off_2 = off_0 + 2;
-
-                       if (order_yc) {
-                               off_0++;
-                               off_2++;
-                       }
-                       if (!order_uv) {
-                               off_0 += 2;
-                               off_2 -= 2;
-                       }
-                       u = chromaLine[off_0] + hue_corr;
-                       v = chromaLine[off_2] + hue2_corr;
-
-                       /* Apply color correction */
-                       if (color_corr != 0) {
-                               /* Magnify up to 2 times, reduce down to zero saturation */
-                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
-                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
-                       }
-                       YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
-               }
-
-       make_pixel:
-               /*
-                * The purpose of creating the pixel here, in one,
-                * dedicated place is that we may need to make the
-                * pixel wider and taller than it actually is. This
-                * may be used if camera generates small frames for
-                * sake of frame rate (or any other reason.)
-                *
-                * The output data consists of B, G, R bytes
-                * (in this order).
-                */
-#if USES_IBMCAM_PUTPIXEL
-               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-#else
-               *f++ = bv;
-               *f++ = gv;
-               *f++ = rv;
-#endif
-               /*
-                * Typically we do not decide within a legitimate frame
-                * that we want to end the frame. However debugging code
-                * may detect marker of new frame within the data. Then
-                * this condition activates. The 'data' pointer is already
-                * pointing at the new marker, so we'd better leave it as is.
-                */
-               if (frame_done)
-                       break;  /* End scanning of lines */
-       }
-       /*
-        * Account for number of bytes that we wrote into output V4L frame.
-        * We do it here, after we are done with the scanline, because we
-        * may fill more than one output scanline if we do vertical
-        * enlargement.
-        */
-       frame->curline += 2;
-       if (pcopylen != NULL)
-               *pcopylen += 2 * v4l_linesize;
-       frame->deinterlace = Deinterlace_FillOddLines;
-
-       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
-               return scan_NextFrame;
-       else
-               return scan_Continue;
-}
-
-/*
- * ibmcam_model2_320x240_parse_lines()
- *
- * This procedure deals with a weird RGB format that is produced by IBM
- * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
- * depending on horizontal size of the picture:
- *
- * <--- 160 or 176 pairs of RA,RB bytes ----->
- * *-----------------------------------------* \
- * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \   This is pair of horizontal lines,
- * |-----+-----+-----+-----+ ... +-----+-----|   *- or one interlaced line, total
- * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   120 or 144 such pairs which yield
- * |=====+=====+=====+=====+ ... +=====+=====| /    240 or 288 lines after deinterlacing.
- *
- * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
- * defines ONE pixel. Therefore this format yields 176x144 "decoded"
- * resolution at best. I do not know why camera sends such format - the
- * previous model (1) just used interlaced I420 and everyone was happy.
- *
- * I do not know what is the difference between RAi and RBi bytes. Both
- * seemingly represent R component, but slightly vary in value (so that
- * the picture looks a bit colored if one or another is used). I use
- * them both as R component in attempt to at least partially recover the
- * lost resolution.
- */
-static enum ParseState ibmcam_model2_320x240_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       unsigned char *f, *la, *lb;
-       unsigned int len;
-       int v4l_linesize; /* V4L line offset */
-       int i, j, frame_done=0, color_corr;
-       int scanLength, scanHeight;
-       static unsigned char lineBuffer[352*2];
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_320x240:
-       case VIDEOSIZE_352x240:
-       case VIDEOSIZE_352x288:
-               scanLength = VIDEOSIZE_X(uvd->videosize);
-               scanHeight = VIDEOSIZE_Y(uvd->videosize);
-               break;
-       default:
-               err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
-               return scan_Out;
-       }
-
-       color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       len = scanLength * 2; /* See explanation above */
-       assert(len <= sizeof(lineBuffer));
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Mind that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
-               return scan_NextFrame;
-
-       la = lineBuffer;
-       lb = lineBuffer + scanLength;
-
-       /*
-        * Now we are sure that entire line (representing all
-        *         VIDEOSIZE_X(frame->request)
-        * pixels from the camera) is available in the scratch buffer. We
-        * start copying the line left-aligned to the V4L buffer (which
-        * might be larger - not smaller, hopefully). If the camera
-        * line is shorter then we should pad the V4L buffer with something
-        * (black in this case) to complete the line.
-        */
-       f = frame->data + (v4l_linesize * frame->curline);
-
-       /* Fill the 2-line strip */
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-               int y, rv, gv, bv;      /* RGB components */
-
-               j = i & (~1);
-
-               /* Check for various visual debugging hints (colorized pixels) */
-               if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
-                       if (IBMCAM_T(uvd)->has_hdr == 1) {
-                               bv = 0; /* Yellow marker */
-                               gv = 0xFF;
-                               rv = 0xFF;
-                       } else {
-                               bv = 0xFF; /* Cyan marker */
-                               gv = 0xFF;
-                               rv = 0;
-                       }
-                       IBMCAM_T(uvd)->has_hdr = 0;
-                       goto make_pixel;
-               }
-
-               /*
-                * Check if we are still in range. We may be out of range if our
-                * V4L canvas is wider or taller than the camera "native" image.
-                * Then we quickly fill the remainder of the line with zeros to
-                * make black color and quit the horizontal scanning loop.
-                */
-               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
-                       const int j = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
-                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
-                       f = frame->data + (v4l_linesize * frame->curline) + j;
-#endif
-                       memset(f, 0, v4l_linesize - j);
-                       break;
-               }
-
-               /*
-                * Here I use RA and RB components, one per physical pixel.
-                * This causes fine vertical grid on the picture but may improve
-                * horizontal resolution. If you prefer replicating, use this:
-                *   rv = la[j + 0];   ... or ... rv = la[j + 1];
-                * then the pixel will be replicated.
-                */
-               rv = la[i];
-               gv = lb[j + 1];
-               bv = lb[j + 0];
-
-               y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
-
-               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
-                       rv = gv = bv = y;
-               else if (color_corr != 128) {
-
-                       /* Calculate difference between color and brightness */
-                       rv -= y;
-                       gv -= y;
-                       bv -= y;
-
-                       /* Scale differences */
-                       rv = (rv * color_corr) / 128;
-                       gv = (gv * color_corr) / 128;
-                       bv = (bv * color_corr) / 128;
-
-                       /* Reapply brightness */
-                       rv += y;
-                       gv += y;
-                       bv += y;
-
-                       /* Watch for overflows */
-                       RESTRICT_TO_RANGE(rv, 0, 255);
-                       RESTRICT_TO_RANGE(gv, 0, 255);
-                       RESTRICT_TO_RANGE(bv, 0, 255);
-               }
-
-       make_pixel:
-               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-       }
-       /*
-        * Account for number of bytes that we wrote into output V4L frame.
-        * We do it here, after we are done with the scanline, because we
-        * may fill more than one output scanline if we do vertical
-        * enlargement.
-        */
-       frame->curline += 2;
-       *pcopylen += v4l_linesize * 2;
-       frame->deinterlace = Deinterlace_FillOddLines;
-
-       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
-               return scan_NextFrame;
-       else
-               return scan_Continue;
-}
-
-static enum ParseState ibmcam_model3_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       unsigned char *data;
-       const unsigned char *color;
-       unsigned int len;
-       int v4l_linesize; /* V4L line offset */
-       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
-       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
-       const int ccm = 128; /* Color correction median - see below */
-       int i, u, v, rw, data_w=0, data_h=0, color_corr;
-       static unsigned char lineBuffer[640*3];
-
-       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       /* The header tells us what sort of data is in this frame */
-       switch (frame->header) {
-               /*
-                * Uncompressed modes (that are easy to decode).
-                */
-       case 0x0308:
-               data_w = 640;
-               data_h = 480;
-               break;
-       case 0x0208:
-               data_w = 320;
-               data_h = 240;
-               break;
-       case 0x020A:
-               data_w = 160;
-               data_h = 120;
-               break;
-               /*
-                * Compressed modes (ViCE - that I don't know how to decode).
-                */
-       case 0x0328:    /* 640x480, best quality compression */
-       case 0x0368:    /* 640x480, best frame rate compression */
-       case 0x0228:    /* 320x240, best quality compression */
-       case 0x0268:    /* 320x240, best frame rate compression */
-       case 0x02CA:    /* 160x120, best quality compression */
-       case 0x02EA:    /* 160x120, best frame rate compression */
-               /* Do nothing with this - not supported */
-               err("Unsupported mode $%04lx", frame->header);
-               return scan_NextFrame;
-       default:
-               /* Catch unknown headers, may help in learning new headers */
-               err("Strange frame->header=$%08lx", frame->header);
-               return scan_NextFrame;
-       }
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Note that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 1) >= data_h) {
-               if (uvd->debug >= 3)
-                       info("Reached line %d. (frame is done)", frame->curline);
-               return scan_NextFrame;
-       }
-
-       /* Make sure there's enough data for the entire line */
-       len = 3 * data_w; /* <y-data> <uv-data> */
-       assert(len <= sizeof(lineBuffer));
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       data = lineBuffer;
-       color = data + data_w;          /* Point to where color planes begin */
-
-       /* Bottom-to-top scanning */
-       rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
-       RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
-
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-               int y, rv, gv, bv;      /* RGB components */
-
-               if (i < data_w) {
-                       y = data[i];    /* Luminosity is the first line */
-
-                       /* Apply static color correction */
-                       u = color[i*2] + hue_corr;
-                       v = color[i*2 + 1] + hue2_corr;
-
-                       /* Apply color correction */
-                       if (color_corr != 0) {
-                               /* Magnify up to 2 times, reduce down to zero saturation */
-                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
-                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
-                       }
-               } else
-                       y = 0, u = v = 128;
-
-               YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
-               RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
-       }
-       frame->deinterlace = Deinterlace_FillEvenLines;
-
-       /*
-        * Account for number of bytes that we wrote into output V4L frame.
-        * We do it here, after we are done with the scanline, because we
-        * may fill more than one output scanline if we do vertical
-        * enlargement.
-        */
-       frame->curline += 2;
-       *pcopylen += 2 * v4l_linesize;
-
-       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
-               if (uvd->debug >= 3) {
-                       info("All requested lines (%ld.) done.",
-                            VIDEOSIZE_Y(frame->request));
-               }
-               return scan_NextFrame;
-       } else
-               return scan_Continue;
-}
-
-/*
- * ibmcam_model4_128x96_parse_lines()
- *
- * This decoder is for one strange data format that is produced by Model 4
- * camera only in 128x96 mode. This is RGB format and here is its description.
- * First of all, this is non-interlaced stream, meaning that all scan lines
- * are present in the datastream. There are 96 consecutive blocks of data
- * that describe all 96 lines of the image. Each block is 5*128 bytes long
- * and carries R, G, B components. The format of the block is shown in the
- * code below. First 128*2 bytes are interleaved R and G components. Then
- * we have a gap (junk data) 64 bytes long. Then follow B and something
- * else, also interleaved (this makes another 128*2 bytes). After that
- * probably another 64 bytes of junk follow.
- *
- * History:
- * 10-Feb-2001 Created.
- */
-static enum ParseState ibmcam_model4_128x96_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       const unsigned char *data_rv, *data_gv, *data_bv;
-       unsigned int len;
-       int i, v4l_linesize; /* V4L line offset */
-       const int data_w=128, data_h=96;
-       static unsigned char lineBuffer[128*5];
-
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Note that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 1) >= data_h) {
-               if (uvd->debug >= 3)
-                       info("Reached line %d. (frame is done)", frame->curline);
-               return scan_NextFrame;
-       }
-
-       /*
-        * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
-        * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
-        */
-
-       /* Make sure there's enough data for the entire line */
-       len = 5 * data_w;
-       assert(len <= sizeof(lineBuffer));
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       data_rv = lineBuffer;
-       data_gv = lineBuffer + 1;
-       data_bv = lineBuffer + data_w*2 + data_w/2;
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-               int rv, gv, bv; /* RGB components */
-               if (i < data_w) {
-                       const int j = i * 2;
-                       gv = data_rv[j];
-                       rv = data_gv[j];
-                       bv = data_bv[j];
-                       if (flags & FLAGS_MONOCHROME) {
-                               unsigned long y;
-                               y = rv + gv + bv;
-                               y /= 3;
-                               if (y > 0xFF)
-                                       y = 0xFF;
-                               rv = gv = bv = (unsigned char) y;
-                       }
-               } else {
-                       rv = gv = bv = 0;
-               }
-               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-       }
-       frame->deinterlace = Deinterlace_None;
-       frame->curline++;
-       *pcopylen += v4l_linesize;
-
-       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
-               if (uvd->debug >= 3) {
-                       info("All requested lines (%ld.) done.",
-                            VIDEOSIZE_Y(frame->request));
-               }
-               return scan_NextFrame;
-       } else
-               return scan_Continue;
-}
-
-/*
- * ibmcam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ibmcam_find_header() or ibmcam_parse_lines() to do most
- * of work.
- *
- * History:
- * 1/21/00  Created.
- */
-static void ibmcam_ProcessIsocData(struct uvd *uvd,
-                                  struct usbvideo_frame *frame)
-{
-       enum ParseState newstate;
-       long copylen = 0;
-       int mod = IBMCAM_T(uvd)->camera_model;
-
-       while (1) {
-               newstate = scan_Out;
-               if (RingQueue_GetLength(&uvd->dp) > 0) {
-                       if (frame->scanstate == ScanState_Scanning) {
-                               newstate = ibmcam_find_header(uvd);
-                       } else if (frame->scanstate == ScanState_Lines) {
-                               if ((mod == IBMCAM_MODEL_2) &&
-                                   ((uvd->videosize == VIDEOSIZE_352x288) ||
-                                    (uvd->videosize == VIDEOSIZE_320x240) ||
-                                    (uvd->videosize == VIDEOSIZE_352x240)))
-                               {
-                                       newstate = ibmcam_model2_320x240_parse_lines(
-                                               uvd, frame, &copylen);
-                               } else if (mod == IBMCAM_MODEL_4) {
-                                       /*
-                                        * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
-                                        * for 320x240 and above; 160x120 and 176x144 uses Model 1
-                                        * decoder (YUV), and 128x96 mode uses ???
-                                        */
-                                       if ((uvd->videosize == VIDEOSIZE_352x288) ||
-                                           (uvd->videosize == VIDEOSIZE_320x240) ||
-                                           (uvd->videosize == VIDEOSIZE_352x240))
-                                       {
-                                               newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
-                                       } else if (uvd->videosize == VIDEOSIZE_128x96) {
-                                               newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
-                                       } else {
-                                               newstate = ibmcam_parse_lines(uvd, frame, &copylen);
-                                       }
-                               } else if (mod == IBMCAM_MODEL_3) {
-                                       newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
-                               } else {
-                                       newstate = ibmcam_parse_lines(uvd, frame, &copylen);
-                               }
-                       }
-               }
-               if (newstate == scan_Continue)
-                       continue;
-               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
-                       break;
-               else
-                       return; /* scan_EndParse */
-       }
-
-       if (newstate == scan_NextFrame) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-               if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
-                       /* Need software contrast adjustment for those cameras */
-                       frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
-               }
-       }
-
-       /* Update the frame's uncompressed length. */
-       frame->seqRead_Length += copylen;
-
-#if 0
-       {
-               static unsigned char j=0;
-               memset(frame->data, j++, uvd->max_frame_size);
-               frame->frameState = FrameState_Ready;
-       }
-#endif
-}
-
-/*
- * ibmcam_veio()
- *
- * History:
- * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ibmcam_veio(
-       struct uvd *uvd,
-       unsigned char req,
-       unsigned short value,
-       unsigned short index)
-{
-       static const char proc[] = "ibmcam_veio";
-       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
-       int i;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return 0;
-
-       if (req == 1) {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_rcvctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
-                       value,
-                       index,
-                       cp,
-                       sizeof(cp),
-                       1000);
-#if 0
-               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)",
-                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-                      req, value, index);
-#endif
-       } else {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_sndctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
-                       value,
-                       index,
-                       NULL,
-                       0,
-                       1000);
-       }
-       if (i < 0) {
-               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
-                   proc, i);
-               uvd->last_error = i;
-       }
-       return i;
-}
-
-/*
- * ibmcam_calculate_fps()
- *
- * This procedure roughly calculates the real frame rate based
- * on FPS code (framerate=NNN option). Actual FPS differs
- * slightly depending on lighting conditions, so that actual frame
- * rate is determined by the camera. Since I don't know how to ask
- * the camera what FPS is now I have to use the FPS code instead.
- *
- * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
- * Corresponding real FPS should be in range [3..30] frames per second.
- * The conversion formula is obvious:
- *
- * real_fps = 3 + (fps_code * 4.5)
- *
- * History:
- * 1/18/00  Created.
- */
-static int ibmcam_calculate_fps(struct uvd *uvd)
-{
-       return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ibmcam_send_FF_04_02()
- *
- * This procedure sends magic 3-command prefix to the camera.
- * The purpose of this prefix is not known.
- *
- * History:
- * 1/2/00   Created.
- */
-static void ibmcam_send_FF_04_02(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
-       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_00_04_06(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0006, 0x0124);
-}
-
-static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-}
-
-static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_send_x_00(uvd, x);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0008, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
-       ibmcam_send_x_01_00_05(uvd, unknown_88);
-       ibmcam_send_x_00_05(uvd, fkey);
-       ibmcam_send_x_00_05_02_08_01(uvd, val);
-       ibmcam_send_x_00_05(uvd, unknown_88);
-       ibmcam_send_x_00_05_02_01(uvd, fkey);
-       ibmcam_send_x_00_05(uvd, unknown_89);
-       ibmcam_send_x_00(uvd, fkey);
-       ibmcam_send_00_04_06(uvd);
-       ibmcam_veio(uvd, 1, 0x0000, 0x0126);
-       ibmcam_send_FF_04_02(uvd);
-}
-
-static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
-       ibmcam_send_x_01_00_05  (uvd, unknown_88);
-       ibmcam_send_x_00_05     (uvd, fkey);
-       ibmcam_send_x_00_05_02  (uvd, val);
-}
-
-static void ibmcam_model2_Packet2(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
-       ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
-}
-
-static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
-       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-       ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
-       ibmcam_veio(uvd, 0, v1,     0x012f);
-       ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
-       ibmcam_veio(uvd, 0, 0xc719, 0x0124);
-       ibmcam_veio(uvd, 0, v2,     0x0127);
-
-       ibmcam_model2_Packet2(uvd);
-}
-
-/*
- * ibmcam_model3_Packet1()
- *
- * 00_0078_012d        
- * 00_0097_012f
- * 00_d141_0124        
- * 00_0096_0127
- * 00_fea8_0124        
-*/
-static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
-       ibmcam_veio(uvd, 0, 0x0078, 0x012d);
-       ibmcam_veio(uvd, 0, v1,     0x012f);
-       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-       ibmcam_veio(uvd, 0, v2,     0x0127);
-       ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-}
-
-static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
-{
-       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-       ibmcam_veio(uvd, 0, 0x0026, 0x012f);
-       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-       ibmcam_veio(uvd, 0, i,      0x0127);
-       ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-       ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0038, 0x012d);
-       ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-       ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-       ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-}
-
-/*
- * ibmcam_adjust_contrast()
- *
- * The contrast value changes from 0 (high contrast) to 15 (low contrast).
- * This is in reverse to usual order of things (such as TV controls), so
- * we reverse it again here.
- *
- * TODO: we probably don't need to send the setup 5 times...
- *
- * History:
- * 1/2/00   Created.
- */
-static void ibmcam_adjust_contrast(struct uvd *uvd)
-{
-       unsigned char a_contrast = uvd->vpic.contrast >> 12;
-       unsigned char new_contrast;
-
-       if (a_contrast >= 16)
-               a_contrast = 15;
-       new_contrast = 15 - a_contrast;
-       if (new_contrast == uvd->vpic_old.contrast)
-               return;
-       uvd->vpic_old.contrast = new_contrast;
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               const int ntries = 5;
-               int i;
-               for (i=0; i < ntries; i++) {
-                       ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
-                       ibmcam_send_FF_04_02(uvd);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_2:
-       case IBMCAM_MODEL_4:
-               /* Models 2, 4 do not have this control; implemented in software. */
-               break;
-       case IBMCAM_MODEL_3:
-       {       /* Preset hardware values */
-               static const struct {
-                       unsigned short cv1;
-                       unsigned short cv2;
-                       unsigned short cv3;
-               } cv[7] = {
-                       { 0x05, 0x05, 0x0f },   /* Minimum */
-                       { 0x04, 0x04, 0x16 },
-                       { 0x02, 0x03, 0x16 },
-                       { 0x02, 0x08, 0x16 },
-                       { 0x01, 0x0c, 0x16 },
-                       { 0x01, 0x0e, 0x16 },
-                       { 0x01, 0x10, 0x16 }    /* Maximum */
-               };
-               int i = a_contrast / 2;
-               RESTRICT_TO_RANGE(i, 0, 6);
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
-               ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
-               ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_change_lighting_conditions()
- *
- * Camera model 1:
- * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
- *
- * Camera model 2:
- * We have 16 levels of lighting, 0 for bright light and up to 15 for
- * low light. But values above 5 or so are useless because camera is
- * not really capable to produce anything worth viewing at such light.
- * This setting may be altered only in certain camera state.
- *
- * Low lighting forces slower FPS. Lighting is set as a module parameter.
- *
- * History:
- * 1/5/00   Created.
- * 2/20/00  Added support for Model 2 cameras.
- */
-static void ibmcam_change_lighting_conditions(struct uvd *uvd)
-{
-       static const char proc[] = "ibmcam_change_lighting_conditions";
-
-       if (debug > 0)
-               info("%s: Set lighting to %hu.", proc, lighting);
-
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               const int ntries = 5;
-               int i;
-               for (i=0; i < ntries; i++)
-                       ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
-               break;
-       }
-       case IBMCAM_MODEL_2:
-#if 0
-               /*
-                * This command apparently requires camera to be stopped. My
-                * experiments showed that it -is- possible to alter the lighting
-                * conditions setting "on the fly", but why bother? This setting does
-                * not work reliably in all cases, so I decided simply to leave the
-                * setting where Xirlink put it - in the camera setup phase. This code
-                * is commented out because it does not work at -any- moment, so its
-                * presence makes no sense. You may use it for experiments.
-                */
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop camera */
-               ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Start camera */
-#endif
-               break;
-       case IBMCAM_MODEL_3:
-       case IBMCAM_MODEL_4:
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_set_sharpness()
- *
- * Cameras model 1 have internal smoothing feature. It is controlled by value in
- * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
- * Recommended value is 4. Cameras model 2 do not have this feature at all.
- */
-static void ibmcam_set_sharpness(struct uvd *uvd)
-{
-       static const char proc[] = "ibmcam_set_sharpness";
-
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
-               unsigned short i, sv;
-
-               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
-               if (debug > 0)
-                       info("%s: Set sharpness to %hu.", proc, sharpness);
-
-               sv = sa[sharpness - SHARPNESS_MIN];
-               for (i=0; i < 2; i++) {
-                       ibmcam_send_x_01_00_05  (uvd, unknown_88);
-                       ibmcam_send_x_00_05             (uvd, sharp_13);
-                       ibmcam_send_x_00_05_02  (uvd, sv);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_2:
-       case IBMCAM_MODEL_4:
-               /* Models 2, 4 do not have this control */
-               break;
-       case IBMCAM_MODEL_3:
-       {       /*
-                * "Use a table of magic numbers.
-                *  This setting doesn't really change much.
-                *  But that's how Windows does it."
-                */
-               static const struct {
-                       unsigned short sv1;
-                       unsigned short sv2;
-                       unsigned short sv3;
-                       unsigned short sv4;
-               } sv[7] = {
-                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
-                       { 0x01, 0x04, 0x05, 0x14 },
-                       { 0x02, 0x04, 0x05, 0x14 },
-                       { 0x03, 0x04, 0x05, 0x14 },
-                       { 0x03, 0x05, 0x05, 0x14 },
-                       { 0x03, 0x06, 0x05, 0x14 },
-                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
-               };
-               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
-               RESTRICT_TO_RANGE(sharpness, 0, 6);
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
-               ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
-               ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
-               ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ibmcam_set_brightness(struct uvd *uvd)
-{
-       static const char proc[] = "ibmcam_set_brightness";
-       static const unsigned short n = 1;
-
-       if (debug > 0)
-               info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
-
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               unsigned short i, j, bv[3];
-               bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
-               if (bv[0] == (uvd->vpic_old.brightness >> 10))
-                       return;
-               uvd->vpic_old.brightness = bv[0];
-               for (j=0; j < 3; j++)
-                       for (i=0; i < n; i++)
-                               ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
-               break;
-       }
-       case IBMCAM_MODEL_2:
-       {
-               unsigned short i, j;
-               i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
-               j = 0x60 + i * ((0xee - 0x60) / 16);    /* 0x60 .. 0xee or so */
-               if (uvd->vpic_old.brightness == j)
-                       break;
-               uvd->vpic_old.brightness = j;
-               ibmcam_model2_Packet1(uvd, mod2_brightness, j);
-               break;
-       }
-       case IBMCAM_MODEL_3:
-       {
-               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
-               unsigned short i =
-                       0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
-               RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
-               if (uvd->vpic_old.brightness == i)
-                       break;
-               uvd->vpic_old.brightness = i;
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x0036, i);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-               break;
-       }
-       case IBMCAM_MODEL_4:
-       {
-               /* Model 4: Brightness range 'i' in [0x04..0xb4] */
-               unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
-               RESTRICT_TO_RANGE(i, 0x04, 0xb4);
-               if (uvd->vpic_old.brightness == i)
-                       break;
-               uvd->vpic_old.brightness = i;
-               ibmcam_model4_BrightnessPacket(uvd, i);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static void ibmcam_set_hue(struct uvd *uvd)
-{
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_2:
-       {
-               unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
-               if (uvd->vpic_old.hue == hue)
-                       return;
-               uvd->vpic_old.hue = hue;
-               ibmcam_model2_Packet1(uvd, mod2_hue, hue);
-               /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
-               break;
-       }
-       case IBMCAM_MODEL_3:
-       {
-#if 0 /* This seems not to work. No problem, will fix programmatically */
-               unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
-               RESTRICT_TO_RANGE(hue, 0x05, 0x37);
-               if (uvd->vpic_old.hue == hue)
-                       return;
-               uvd->vpic_old.hue = hue;
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x007e, hue);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-#endif
-               break;
-       }
-       case IBMCAM_MODEL_4:
-       {
-               unsigned short r_gain, g_gain, b_gain, hue;
-
-               /*
-                * I am not sure r/g/b_gain variables exactly control gain
-                * of those channels. Most likely they subtly change some
-                * very internal image processing settings in the camera.
-                * In any case, here is what they do, and feel free to tweak:
-                *
-                * r_gain: seriously affects red gain
-                * g_gain: seriously affects green gain
-                * b_gain: seriously affects blue gain
-                * hue: changes average color from violet (0) to red (0xFF)
-                *
-                * These settings are preset for a decent white balance in
-                * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
-                * and therefore may need different values here.
-                */
-               hue = 20 + (uvd->vpic.hue >> 9);
-               switch (uvd->videosize) {
-               case VIDEOSIZE_128x96:
-                       r_gain = 90;
-                       g_gain = 166;
-                       b_gain = 175;
-                       break;
-               case VIDEOSIZE_160x120:
-                       r_gain = 70;
-                       g_gain = 166;
-                       b_gain = 185;
-                       break;
-               case VIDEOSIZE_176x144:
-                       r_gain = 160;
-                       g_gain = 175;
-                       b_gain = 185;
-                       break;
-               default:
-                       r_gain = 120;
-                       g_gain = 166;
-                       b_gain = 175;
-                       break;
-               }
-               RESTRICT_TO_RANGE(hue, 1, 0x7f);
-
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, g_gain, 0x0127);    /* Green gain */
-               ibmcam_veio(uvd, 0, r_gain, 0x012e);    /* Red gain */
-               ibmcam_veio(uvd, 0, b_gain, 0x0130);    /* Blue gain */
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, hue,    0x012d);    /* Hue */
-               ibmcam_veio(uvd, 0, 0xf545, 0x0124);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ibmcam_adjust_picture(struct uvd *uvd)
-{
-       ibmcam_adjust_contrast(uvd);
-       ibmcam_set_brightness(uvd);
-       ibmcam_set_hue(uvd);
-}
-
-static int ibmcam_model1_setup(struct uvd *uvd)
-{
-       const int ntries = 5;
-       int i;
-
-       ibmcam_veio(uvd, 1, 0x00, 0x0128);
-       ibmcam_veio(uvd, 1, 0x00, 0x0100);
-       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
-       ibmcam_veio(uvd, 1, 0x00, 0x0100);
-       ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
-       ibmcam_veio(uvd, 1, 0x00, 0x0100);
-       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
-       ibmcam_veio(uvd, 0, 0x01, 0x0108);
-
-       ibmcam_veio(uvd, 0, 0x03, 0x0112);
-       ibmcam_veio(uvd, 1, 0x00, 0x0115);
-       ibmcam_veio(uvd, 0, 0x06, 0x0115);
-       ibmcam_veio(uvd, 1, 0x00, 0x0116);
-       ibmcam_veio(uvd, 0, 0x44, 0x0116);
-       ibmcam_veio(uvd, 1, 0x00, 0x0116);
-       ibmcam_veio(uvd, 0, 0x40, 0x0116);
-       ibmcam_veio(uvd, 1, 0x00, 0x0115);
-       ibmcam_veio(uvd, 0, 0x0e, 0x0115);
-       ibmcam_veio(uvd, 0, 0x19, 0x012c);
-
-       ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x09);
-       ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
-       ibmcam_Packet_Format1(uvd, 0x28, 0x22);
-       ibmcam_Packet_Format1(uvd, light_27, 0);
-       ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
-
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
-
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x30, 0x14);
-
-       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
-       ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
-       ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
-       ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
-       ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
-       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
-       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
-       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
-       ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
-       ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
-       ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
-       ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
-       ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
-       ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
-       ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
-       ibmcam_PacketFormat2(uvd, 0x11, 0xba);
-       ibmcam_PacketFormat2(uvd, 0x12, 0x53);
-       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
-       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
-       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
-       ibmcam_PacketFormat2(uvd, 0x16, 0x00);
-       ibmcam_PacketFormat2(uvd, 0x17, 0x28);
-       ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
-       ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
-       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
-       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x00, 0x18);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x13, 0x18);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x14, 0x06);
-
-       /* This is default brightness */
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x31, 0x37);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x32, 0x46);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x33, 0x55);
-
-       ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x29, 0x80);
-       ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
-       ibmcam_Packet_Format1(uvd, 0x30, 0x17);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x34, 0x00);
-
-       ibmcam_veio(uvd, 0, 0x00, 0x0101);
-       ibmcam_veio(uvd, 0, 0x00, 0x010a);
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_128x96:
-               ibmcam_veio(uvd, 0, 0x80, 0x0103);
-               ibmcam_veio(uvd, 0, 0x60, 0x0105);
-               ibmcam_veio(uvd, 0, 0x0c, 0x010b);
-               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x0b, 0x011d);
-               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x00, 0x0129);
-               break;
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
-               ibmcam_veio(uvd, 0, 0x8f, 0x0105);
-               ibmcam_veio(uvd, 0, 0x06, 0x010b);
-               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x0d, 0x011d);
-               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x03, 0x0129);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
-               ibmcam_veio(uvd, 0, 0x90, 0x0105);
-               ibmcam_veio(uvd, 0, 0x02, 0x010b);
-               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x05, 0x011d);
-               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x00, 0x0129);
-               break;
-       }
-
-       ibmcam_veio(uvd, 0, 0xff, 0x012b);
-
-       /* This is another brightness - don't know why */
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
-
-       /* Default contrast */
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
-
-       /* Default sharpness */
-       for (i=0; i < 2; i++)
-               ibmcam_PacketFormat2(uvd, sharp_13, 0x1a);      /* Level 4 FIXME */
-
-       /* Default lighting conditions */
-       ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
-
-       /* Assorted init */
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_128x96:
-               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
-               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x36, 0x0102);
-               ibmcam_veio(uvd, 0, 0x1a, 0x0104);
-               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
-               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
-#if 0
-               ibmcam_veio(uvd, 0, 0x00, 0x0106);
-               ibmcam_veio(uvd, 0, 0x38, 0x0107);
-#else
-               ibmcam_veio(uvd, 0, 0x02, 0x0106);
-               ibmcam_veio(uvd, 0, 0x2a, 0x0107);
-#endif
-               break;
-       case VIDEOSIZE_176x144:
-               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
-               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x04, 0x0102);
-               ibmcam_veio(uvd, 0, 0x02, 0x0104);
-               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
-               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x01, 0x0106);
-               ibmcam_veio(uvd, 0, 0xca, 0x0107);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
-               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x08, 0x0102);
-               ibmcam_veio(uvd, 0, 0x01, 0x0104);
-               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x2f, 0x011c);
-               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x03, 0x0106);
-               ibmcam_veio(uvd, 0, 0xf6, 0x0107);
-               break;
-       }
-       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-static int ibmcam_model2_setup(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
-       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
-       ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-       ibmcam_veio(uvd, 0, 0x0008, 0x012b);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
-               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);    /* Unique to this mode */
-               ibmcam_veio(uvd, 0, 0x0038, 0x0119);    /* Unique to this mode */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0090, 0x0107);    /* Unique to every mode*/
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);    /* Unique to this mode */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0098, 0x0107);    /* Unique to every mode*/
-               break;
-       case VIDEOSIZE_352x240:
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x00da, 0x0107);    /* Unique to every mode*/
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x00fe, 0x0107);    /* Unique to every mode*/
-               break;
-       }
-       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-/*
- * ibmcam_model1_setup_after_video_if()
- *
- * This code adds finishing touches to the video data interface.
- * Here we configure the frame rate and turn on the LED.
- */
-static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
-{
-       unsigned short internal_frame_rate;
-
-       RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
-       internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
-       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
-       ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
-       ibmcam_veio(uvd, 0, 0x01, 0x0114);
-       ibmcam_veio(uvd, 0, 0xc0, 0x010c);
-}
-
-static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
-{
-       unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
-
-       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0x0050, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               break;
-       case VIDEOSIZE_320x240:
-       case VIDEOSIZE_352x240:
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0x0040, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               break;
-       }
-       ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-       ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-
-       /*
-        * Hardware settings, may affect CMOS sensor; not user controls!
-        * -------------------------------------------------------------
-        * 0x0004: no effect
-        * 0x0006: hardware effect
-        * 0x0008: no effect
-        * 0x000a: stops video stream, probably important h/w setting
-        * 0x000c: changes color in hardware manner (not user setting)
-        * 0x0012: changes number of colors (does not affect speed)
-        * 0x002a: no effect
-        * 0x002c: hardware setting (related to scan lines)
-        * 0x002e: stops video stream, probably important h/w setting
-        */
-       ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
-       ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
-       ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
-       ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
-       ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
-
-       /*
-        * Function 0x0030 pops up all over the place. Apparently
-        * it is a hardware control register, with every bit assigned to
-        * do something.
-        */
-       ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
-
-       /*
-        * Magic control of CMOS sensor. Only lower values like
-        * 0-3 work, and picture shifts left or right. Don't change.
-        */
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
-               break;
-       case VIDEOSIZE_352x240:
-               /* This mode doesn't work as Windows programs it; changed to work */
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
-               break;
-       }
-
-       ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
-
-       /*
-        * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
-        * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
-        * slowest setting. However for all practical reasons high settings make no
-        * sense because USB is not fast enough to support high FPS. Be aware that
-        * the picture datastream will be severely disrupted if you ask for
-        * frame rate faster than allowed for the video size - see below:
-        *
-        * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
-        * -----------------------------------------------------------------
-        * 176x144: [6..31]
-        * 320x240: [8..31]
-        * 352x240: [10..31]
-        * 352x288: [16..31] I have to raise lower threshold for stability...
-        *
-        * As usual, slower FPS provides better sensitivity.
-        */
-       {
-               short hw_fps=31, i_framerate;
-
-               RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
-               i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
-               switch (uvd->videosize) {
-               case VIDEOSIZE_176x144:
-                       hw_fps = 6 + i_framerate*4;
-                       break;
-               case VIDEOSIZE_320x240:
-                       hw_fps = 8 + i_framerate*3;
-                       break;
-               case VIDEOSIZE_352x240:
-                       hw_fps = 10 + i_framerate*2;
-                       break;
-               case VIDEOSIZE_352x288:
-                       hw_fps = 28 + i_framerate/2;
-                       break;
-               }
-               if (uvd->debug > 0)
-                       info("Framerate (hardware): %hd.", hw_fps);
-               RESTRICT_TO_RANGE(hw_fps, 0, 31);
-               ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
-       }
-
-       /*
-        * This setting does not visibly affect pictures; left it here
-        * because it was present in Windows USB data stream. This function
-        * does not allow arbitrary values and apparently is a bit mask, to
-        * be activated only at appropriate time. Don't change it randomly!
-        */
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
-               break;
-       case VIDEOSIZE_352x240:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
-               break;
-       }
-
-       ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
-
-       if (init_model2_rg2 >= 0) {
-               RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
-               setup_model2_rg2 = init_model2_rg2;
-       } else
-               setup_model2_rg2 = 0x002f;
-
-       if (init_model2_sat >= 0) {
-               RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
-               setup_model2_sat = init_model2_sat;
-       } else
-               setup_model2_sat = 0x0034;
-
-       if (init_model2_yb >= 0) {
-               RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
-               setup_model2_yb = init_model2_yb;
-       } else
-               setup_model2_yb = 0x00a0;
-
-       ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
-       ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
-       ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
-       ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
-
-       /* Hardware control command */
-       ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
-       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go camera, go! */
-       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
-{
-       switch (uvd->videosize) {
-       case VIDEOSIZE_128x96:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_160x120:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000b, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0025, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0048, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0035, 0x012e);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0048, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0090, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x0018, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0007, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0001, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x002a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
-               ibmcam_veio(uvd, 0, 0x006d, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x008c, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0006, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0002, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0025, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0048, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break; 
-       }
-       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
-{
-       int i;
-       /*
-        * 01.01.08 - Added for RCA video in support -LO
-        * This struct is used to init the Model3 cam to use the RCA video in port
-        * instead of the CCD sensor.
-        */
-       static const struct struct_initData initData[] = {
-               {0, 0x0000, 0x010c},
-               {0, 0x0006, 0x012c},
-               {0, 0x0078, 0x012d},
-               {0, 0x0046, 0x012f},
-               {0, 0xd141, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfea8, 0x0124},
-               {1, 0x0000, 0x0116},
-               {0, 0x0064, 0x0116},
-               {1, 0x0000, 0x0115},
-               {0, 0x0003, 0x0115},
-               {0, 0x0008, 0x0123},
-               {0, 0x0000, 0x0117},
-               {0, 0x0000, 0x0112},
-               {0, 0x0080, 0x0100},
-               {0, 0x0000, 0x0100},
-               {1, 0x0000, 0x0116},
-               {0, 0x0060, 0x0116},
-               {0, 0x0002, 0x0112},
-               {0, 0x0000, 0x0123},
-               {0, 0x0001, 0x0117},
-               {0, 0x0040, 0x0108},
-               {0, 0x0019, 0x012c},
-               {0, 0x0040, 0x0116},
-               {0, 0x000a, 0x0115},
-               {0, 0x000b, 0x0115},
-               {0, 0x0078, 0x012d},
-               {0, 0x0046, 0x012f},
-               {0, 0xd141, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfea8, 0x0124},
-               {0, 0x0064, 0x0116},
-               {0, 0x0000, 0x0115},
-               {0, 0x0001, 0x0115},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00aa, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f2, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x000f, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f8, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00fc, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f9, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x003c, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0027, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0019, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0021, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0006, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0045, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002a, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x000e, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002b, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f4, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002c, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0004, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002d, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0014, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002e, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0003, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002f, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0003, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0014, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0053, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0x0000, 0x0101},
-               {0, 0x00a0, 0x0103},
-               {0, 0x0078, 0x0105},
-               {0, 0x0000, 0x010a},
-               {0, 0x0024, 0x010b},
-               {0, 0x0028, 0x0119},
-               {0, 0x0088, 0x011b},
-               {0, 0x0002, 0x011d},
-               {0, 0x0003, 0x011e},
-               {0, 0x0000, 0x0129},
-               {0, 0x00fc, 0x012b},
-               {0, 0x0008, 0x0102},
-               {0, 0x0000, 0x0104},
-               {0, 0x0008, 0x011a},
-               {0, 0x0028, 0x011c},
-               {0, 0x0021, 0x012a},
-               {0, 0x0000, 0x0118},
-               {0, 0x0000, 0x0132},
-               {0, 0x0000, 0x0109},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0031, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00dc, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0032, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0020, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0030, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0008, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0x0003, 0x0106},
-               {0, 0x0062, 0x0107},
-               {0, 0x0003, 0x0111},
-       };
-#define NUM_INIT_DATA 
-
-       unsigned short compression = 0; /* 0=none, 7=best frame rate  */
-       int f_rate; /* 0=Fastest 7=slowest */
-
-       if (IBMCAM_T(uvd)->initialized)
-               return;
-
-       /* Internal frame rate is controlled by f_rate value */
-       f_rate = 7 - framerate;
-       RESTRICT_TO_RANGE(f_rate, 0, 7);
-
-       ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0123);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0117);
-       ibmcam_veio(uvd, 0, 0x0040, 0x0108);
-       ibmcam_veio(uvd, 0, 0x0019, 0x012c);
-       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0115);
-       ibmcam_veio(uvd, 0, 0x0003, 0x0115);
-       ibmcam_veio(uvd, 1, 0x0000, 0x0115);
-       ibmcam_veio(uvd, 0, 0x000b, 0x0115);
-       ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
-       ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
-       ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
-       ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
-       ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
-       ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
-       ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
-       ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
-       ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
-       ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
-       ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
-       ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
-       ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
-       ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
-       ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
-       ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
-       ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
-       ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
-       ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
-       ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
-       ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
-       ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
-       ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
-       ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
-       ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
-       ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
-       ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
-       ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
-       ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
-       ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
-       ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
-       ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
-       ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
-       ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
-       ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_160x120:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
-               ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
-               ibmcam_veio(uvd, 0, 0x0016, 0x011b);
-               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
-               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
-               ibmcam_veio(uvd, 0, 0x0018, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
-               ibmcam_veio(uvd, 0, 0x0028, 0x011c);
-               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0118);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
-               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
-               ibmcam_veio(uvd, 0, compression, 0x0109);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
-               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
-               ibmcam_veio(uvd, 0, 0x0000, 0x011e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
-               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
-               /* 4 commands from 160x120 skipped */
-               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
-               ibmcam_veio(uvd, 0, compression, 0x0109);
-               ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
-               ibmcam_veio(uvd, 0, 0x0006, 0x011b);
-               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0010, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
-               ibmcam_veio(uvd, 0, 0x003f, 0x011c);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0118);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
-               break;
-       case VIDEOSIZE_640x480:
-               ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
-               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
-               ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
-               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
-               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
-               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
-               ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
-               ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
-               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
-               ibmcam_veio(uvd, 0, compression, 0x0109);
-               ibmcam_veio(uvd, 0, 0x0040, 0x0101);
-               ibmcam_veio(uvd, 0, 0x0040, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
-               break;
-       }
-       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);     /* Hue */
-       ibmcam_model3_Packet1(uvd, 0x0036, 0x0011);     /* Brightness */
-       ibmcam_model3_Packet1(uvd, 0x0060, 0x0002);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0061, 0x0004);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0062, 0x0005);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0063, 0x0014);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
-       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
-       ibmcam_model3_Packet1(uvd, 0x0067, 0x0001);     /* Contrast */
-       ibmcam_model3_Packet1(uvd, 0x005b, 0x000c);     /* Contrast */
-       ibmcam_model3_Packet1(uvd, 0x005c, 0x0016);     /* Contrast */
-       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x002c, 0x0003);     /* Was 1, broke 640x480 */
-       ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
-       ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
-       ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
-       ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
-       ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
-       ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
-       ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
-       ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
-       ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
-       ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
-       ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
-       ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
-       ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
-       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
-       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
-       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_160x120:
-               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0107);
-               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
-               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
-               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x0062, 0x0107);
-               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
-               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
-               ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
-               break;
-       case VIDEOSIZE_640x480:
-               ibmcam_veio(uvd, 0, 0x0002, 0x0106);    /* Adjustments */
-               ibmcam_veio(uvd, 0, 0x00b4, 0x0107);    /* Adjustments */
-               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
-               ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
-               ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
-               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
-               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
-               break;
-       }
-
-       /* 01.01.08 - Added for RCA video in support -LO */
-       if(init_model3_input) {
-               if (debug > 0)
-                       info("Setting input to RCA.");
-               for (i=0; i < ARRAY_SIZE(initData); i++) {
-                       ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
-               }
-       }
-
-       ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-/*
- * ibmcam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ibmcam_video_stop(struct uvd *uvd)
-{
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-               ibmcam_veio(uvd, 0, 0x00, 0x010c);
-               ibmcam_veio(uvd, 0, 0x00, 0x010c);
-               ibmcam_veio(uvd, 0, 0x01, 0x0114);
-               ibmcam_veio(uvd, 0, 0xc0, 0x010c);
-               ibmcam_veio(uvd, 0, 0x00, 0x010c);
-               ibmcam_send_FF_04_02(uvd);
-               ibmcam_veio(uvd, 1, 0x00, 0x0100);
-               ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
-               break;
-       case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop the camera */
-
-               ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
-               ibmcam_veio(uvd, 0, 0x0080, 0x0100);    /* LED Off */
-               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
-
-               ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
-
-               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
-               break;
-       case IBMCAM_MODEL_3:
-#if 1
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);
-
-               /* Here we are supposed to select video interface alt. setting 0 */
-               ibmcam_veio(uvd, 0, 0x0006, 0x012c);
-
-               ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
-
-               ibmcam_veio(uvd, 1, 0x0000, 0x0116);
-               ibmcam_veio(uvd, 0, 0x0064, 0x0116);
-               ibmcam_veio(uvd, 1, 0x0000, 0x0115);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0115);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0123);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0117);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
-               ibmcam_veio(uvd, 0, 0x0080, 0x0100);
-               IBMCAM_T(uvd)->initialized = 0;
-#endif
-               break;
-       } /* switch */
-}
-
-/*
- * ibmcam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- *
- * History:
- * 1/2/00   Created.
- */
-static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
-{
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-               if (do_stop)
-                       ibmcam_video_stop(uvd);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_model1_setup_after_video_if(uvd);
-               break;
-       case IBMCAM_MODEL_2:
-               ibmcam_model2_setup_after_video_if(uvd);
-               break;
-       case IBMCAM_MODEL_3:
-               ibmcam_video_stop(uvd);
-               ibmcam_model3_setup_after_video_if(uvd);
-               break;
-       case IBMCAM_MODEL_4:
-               ibmcam_model4_setup_after_video_if(uvd);
-               break;
-       }
-}
-
-static void ibmcam_video_start(struct uvd *uvd)
-{
-       ibmcam_change_lighting_conditions(uvd);
-       ibmcam_set_sharpness(uvd);
-       ibmcam_reinit_iso(uvd, 0);
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ibmcam_setup_on_open(struct uvd *uvd)
-{
-       int setup_ok = 0; /* Success by default */
-       /* Send init sequence only once, it's large! */
-       if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
-               switch (IBMCAM_T(uvd)->camera_model) {
-               case IBMCAM_MODEL_1:
-                       setup_ok = ibmcam_model1_setup(uvd);
-                       break;
-               case IBMCAM_MODEL_2:
-                       setup_ok = ibmcam_model2_setup(uvd);
-                       break;
-               case IBMCAM_MODEL_3:
-               case IBMCAM_MODEL_4:
-                       /* We do all setup when Isoc stream is requested */
-                       break;
-               }
-               IBMCAM_T(uvd)->initialized = (setup_ok != 0);
-       }
-       return setup_ok;
-}
-
-static void ibmcam_configure_video(struct uvd *uvd)
-{
-       if (uvd == NULL)
-               return;
-
-       RESTRICT_TO_RANGE(init_brightness, 0, 255);
-       RESTRICT_TO_RANGE(init_contrast, 0, 255);
-       RESTRICT_TO_RANGE(init_color, 0, 255);
-       RESTRICT_TO_RANGE(init_hue, 0, 255);
-       RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       uvd->vpic.colour = init_color << 8;
-       uvd->vpic.hue = init_hue << 8;
-       uvd->vpic.brightness = init_brightness << 8;
-       uvd->vpic.contrast = init_contrast << 8;
-       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
-       uvd->vpic.depth = 24;
-       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "IBM USB Camera");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
-       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
-       uvd->vcap.minwidth = min_canvasWidth;
-       uvd->vcap.minheight = min_canvasHeight;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ibmcam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like IBM C-it camera.
- *
- * History:
- * 22-Jan-2000 Moved camera init code to ibmcam_open()
- * 27=Jan-2000 Changed to use static structures, added locking.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 03-Jul-2000 Fixed endianness bug.
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct uvd *uvd = NULL;
-       int ix, i, nas, model=0, canvasX=0, canvasY=0;
-       int actInterface=-1, inactInterface=-1, maxPS=0;
-       __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
-       unsigned char video_ep = 0;
-
-       if (debug >= 1)
-               info("ibmcam_probe(%p,%u.)", intf, ifnum);
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       /* Check the version/revision */
-       switch (le16_to_cpu(dev->descriptor.bcdDevice)) {
-       case 0x0002:
-               if (ifnum != 2)
-                       return -ENODEV;
-               model = IBMCAM_MODEL_1;
-               break;
-       case 0x030A:
-               if (ifnum != 0)
-                       return -ENODEV;
-               if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) ||
-                   (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID))
-                       model = IBMCAM_MODEL_4;
-               else
-                       model = IBMCAM_MODEL_2;
-               break;
-       case 0x0301:
-               if (ifnum != 0)
-                       return -ENODEV;
-               model = IBMCAM_MODEL_3;
-               break;
-       default:
-               err("IBM camera with revision 0x%04x is not supported.",
-                       le16_to_cpu(dev->descriptor.bcdDevice));
-               return -ENODEV;
-       }
-
-       /* Print detailed info on what we found so far */
-       do {
-               char *brand = NULL;
-               switch (le16_to_cpu(dev->descriptor.idProduct)) {
-               case NETCAM_PRODUCT_ID:
-                       brand = "IBM NetCamera";
-                       break;
-               case VEO_800C_PRODUCT_ID:
-                       brand = "Veo Stingray [800C]";
-                       break;
-               case VEO_800D_PRODUCT_ID:
-                       brand = "Veo Stingray [800D]";
-                       break;
-               case IBMCAM_PRODUCT_ID:
-               default:
-                       brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
-                       break;
-               }
-               info("%s USB camera found (model %d, rev. 0x%04x)",
-                    brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
-       } while (0);
-
-       /* Validate found interface: must have one ISO endpoint */
-       nas = intf->num_altsetting;
-       if (debug > 0)
-               info("Number of alternate settings=%d.", nas);
-       if (nas < 2) {
-               err("Too few alternate settings for this camera!");
-               return -ENODEV;
-       }
-       /* Validate all alternate settings */
-       for (ix=0; ix < nas; ix++) {
-               const struct usb_host_interface *interface;
-               const struct usb_endpoint_descriptor *endpoint;
-
-               interface = &intf->altsetting[ix];
-               i = interface->desc.bAlternateSetting;
-               if (interface->desc.bNumEndpoints != 1) {
-                       err("Interface %d. has %u. endpoints!",
-                           ifnum, (unsigned)(interface->desc.bNumEndpoints));
-                       return -ENODEV;
-               }
-               endpoint = &interface->endpoint[0].desc;
-               if (video_ep == 0)
-                       video_ep = endpoint->bEndpointAddress;
-               else if (video_ep != endpoint->bEndpointAddress) {
-                       err("Alternate settings have different endpoint addresses!");
-                       return -ENODEV;
-               }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
-                       err("Interface %d. has non-ISO endpoint!", ifnum);
-                       return -ENODEV;
-               }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
-                       err("Interface %d. has ISO OUT endpoint!", ifnum);
-                       return -ENODEV;
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
-                       if (inactInterface < 0)
-                               inactInterface = i;
-                       else {
-                               err("More than one inactive alt. setting!");
-                               return -ENODEV;
-                       }
-               } else {
-                       if (actInterface < 0) {
-                               actInterface = i;
-                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-                               if (debug > 0)
-                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
-                       } else
-                               err("More than one active alt. setting! Ignoring #%d.", i);
-               }
-       }
-       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
-               err("Failed to recognize the camera!");
-               return -ENODEV;
-       }
-
-       /* Validate options */
-       switch (model) {
-       case IBMCAM_MODEL_1:
-               RESTRICT_TO_RANGE(lighting, 0, 2);
-               RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
-               if (framerate < 0)
-                       framerate = 2;
-               canvasX = 352;
-               canvasY = 288;
-               break;
-       case IBMCAM_MODEL_2:
-               RESTRICT_TO_RANGE(lighting, 0, 15);
-               RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
-               if (framerate < 0)
-                       framerate = 2;
-               canvasX = 352;
-               canvasY = 240;
-               break;
-       case IBMCAM_MODEL_3:
-               RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
-               switch (size) {
-               case SIZE_160x120:
-                       canvasX = 160;
-                       canvasY = 120;
-                       if (framerate < 0)
-                               framerate = 2;
-                       RESTRICT_TO_RANGE(framerate, 0, 5);
-                       break;
-               default:
-                       info("IBM camera: using 320x240");
-                       size = SIZE_320x240;
-                       /* No break here */
-               case SIZE_320x240:
-                       canvasX = 320;
-                       canvasY = 240;
-                       if (framerate < 0)
-                               framerate = 3;
-                       RESTRICT_TO_RANGE(framerate, 0, 5);
-                       break;
-               case SIZE_640x480:
-                       canvasX = 640;
-                       canvasY = 480;
-                       framerate = 0;  /* Slowest, and maybe even that is too fast */
-                       break;
-               }
-               break;
-       case IBMCAM_MODEL_4:
-               RESTRICT_TO_RANGE(lighting, 0, 2);
-               switch (size) {
-               case SIZE_128x96:
-                       canvasX = 128;
-                       canvasY = 96;
-                       break;
-               case SIZE_160x120:
-                       canvasX = 160;
-                       canvasY = 120;
-                       break;
-               default:
-                       info("IBM NetCamera: using 176x144");
-                       size = SIZE_176x144;
-                       /* No break here */
-               case SIZE_176x144:
-                       canvasX = 176;
-                       canvasY = 144;
-                       break;
-               case SIZE_320x240:
-                       canvasX = 320;
-                       canvasY = 240;
-                       break;
-               case SIZE_352x288:
-                       canvasX = 352;
-                       canvasY = 288;
-                       break;
-               }
-               break;
-       default:
-               err("IBM camera: Model %d. not supported!", model);
-               return -ENODEV;
-       }
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (uvd != NULL) {
-               /* Here uvd is a fully allocated uvd object */
-               uvd->flags = flags;
-               uvd->debug = debug;
-               uvd->dev = dev;
-               uvd->iface = ifnum;
-               uvd->ifaceAltInactive = inactInterface;
-               uvd->ifaceAltActive = actInterface;
-               uvd->video_endp = video_ep;
-               uvd->iso_packet_len = maxPS;
-               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
-               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-               uvd->canvas = VIDEOSIZE(canvasX, canvasY);
-               uvd->videosize = ibmcam_size_to_videosize(size);
-
-               /* Initialize ibmcam-specific data */
-               assert(IBMCAM_T(uvd) != NULL);
-               IBMCAM_T(uvd)->camera_model = model;
-               IBMCAM_T(uvd)->initialized = 0;
-
-               ibmcam_configure_video(uvd);
-
-               i = usbvideo_RegisterVideoDevice(uvd);
-               if (i != 0) {
-                       err("usbvideo_RegisterVideoDevice() failed.");
-                       uvd = NULL;
-               }
-       }
-       usb_set_intfdata (intf, uvd);
-       return 0;
-}
-
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },        /* Model 1 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 2 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },        /* Model 3 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 4 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 2 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 4 */
-       { }  /* Terminating entry */
-};
-
-/*
- * ibmcam_init()
- *
- * This code is run to initialize the driver.
- *
- * History:
- * 1/27/00  Reworked to use statically allocated ibmcam structures.
- * 21/10/00 Completely redesigned to use usbvideo services.
- */
-static int __init ibmcam_init(void)
-{
-       struct usbvideo_cb cbTbl;
-       memset(&cbTbl, 0, sizeof(cbTbl));
-       cbTbl.probe = ibmcam_probe;
-       cbTbl.setupOnOpen = ibmcam_setup_on_open;
-       cbTbl.videoStart = ibmcam_video_start;
-       cbTbl.videoStop = ibmcam_video_stop;
-       cbTbl.processData = ibmcam_ProcessIsocData;
-       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
-       cbTbl.adjustPicture = ibmcam_adjust_picture;
-       cbTbl.getFPS = ibmcam_calculate_fps;
-       return usbvideo_register(
-               &cams,
-               MAX_IBMCAM,
-               sizeof(ibmcam_t),
-               "ibmcam",
-               &cbTbl,
-               THIS_MODULE,
-               id_table);
-}
-
-static void __exit ibmcam_cleanup(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-module_init(ibmcam_init);
-module_exit(ibmcam_cleanup);
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
deleted file mode 100644 (file)
index e2ede58..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- * konicawc.c - konica webcam driver
- *
- * Author: Simon Evans <spse@secret.org.uk>
- *
- * Copyright (C) 2002 Simon Evans
- *
- * Licence: GPL
- *
- * Driver for USB webcams based on Konica chipset. This
- * chipset is used in Intel YC76 camera.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb_input.h>
-
-#include "usbvideo.h"
-
-#define MAX_BRIGHTNESS 108
-#define MAX_CONTRAST   108
-#define MAX_SATURATION 108
-#define MAX_SHARPNESS  108
-#define MAX_WHITEBAL   372
-#define MAX_SPEED      6
-
-
-#define MAX_CAMERAS    1
-
-#define DRIVER_VERSION "v1.4"
-#define DRIVER_DESC    "Konica Webcam driver"
-
-enum ctrl_req {
-       SetWhitebal     = 0x01,
-       SetBrightness   = 0x02,
-        SetSharpness   = 0x03,
-       SetContrast     = 0x04,
-       SetSaturation   = 0x05,
-};
-
-
-enum frame_sizes {
-       SIZE_160X120    = 0,
-       SIZE_160X136    = 1,
-       SIZE_176X144    = 2,
-       SIZE_320X240    = 3,
-       
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-static struct usbvideo *cams;
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
-       if (n <= debug) {        \
-               printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
-       }
-#else
-#define DEBUG(n, arg...)
-static const int debug = 0;
-#endif
-
-
-/* Some default values for initial camera settings,
-   can be set by modprobe */
-
-static int size;       
-static int speed = 6;          /* Speed (fps) 0 (slowest) to 6 (fastest) */
-static int brightness =        MAX_BRIGHTNESS/2;
-static int contrast =  MAX_CONTRAST/2;
-static int saturation =        MAX_SATURATION/2;
-static int sharpness = MAX_SHARPNESS/2;
-static int whitebal =  3*(MAX_WHITEBAL/4);
-
-static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
-
-/* These FPS speeds are from the windows config box. They are
- * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
- * real fps.
- */
-
-static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
-                              { 24, 40, 48, 60, 72, 80, 100 },
-                              { 18, 30, 36, 45, 54, 60, 75  },
-                              { 6,  10, 12, 15, 18, 21, 25  } };
-
-struct cam_size {
-       u16     width;
-       u16     height;
-       u8      cmd;
-};
-
-static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
-                                         { 160, 136, 0xa },
-                                         { 176, 144, 0x4 },
-                                         { 320, 240, 0x5 } };
-
-struct konicawc {
-       u8 brightness;          /* camera uses 0 - 9, x11 for real value */
-       u8 contrast;            /* as above */
-       u8 saturation;          /* as above */
-       u8 sharpness;           /* as above */
-       u8 white_bal;           /* 0 - 33, x11 for real value */
-       u8 speed;               /* Stored as 0 - 6, used as index in spd_to_* (above) */
-       u8 size;                /* Frame Size */
-       int height;
-       int width;
-       struct urb *sts_urb[USBVIDEO_NUMSBUF];
-       u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
-       struct urb *last_data_urb;
-       int lastframe;
-       int cur_frame_size;     /* number of bytes in current frame size */
-       int maxline;            /* number of lines per frame */
-       int yplanesz;           /* Number of bytes in the Y plane */
-       unsigned int buttonsts:1;
-#ifdef CONFIG_INPUT
-       struct input_dev *input;
-       char input_physname[64];
-#endif
-};
-
-
-#define konicawc_set_misc(uvd, req, value, index)              konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
-#define konicawc_get_misc(uvd, req, value, index, buf, sz)     konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
-#define konicawc_set_value(uvd, value, index)                  konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
-
-
-static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
-{
-        int retval = usb_control_msg(uvd->dev,
-               dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
-                   request, 0x40 | dir, value, index, buf, len, 1000);
-        return retval < 0 ? retval : 0;
-}
-
-
-static inline void konicawc_camera_on(struct uvd *uvd)
-{
-        DEBUG(0, "camera on");
-        konicawc_set_misc(uvd, 0x2, 1, 0x0b);
-}
-
-
-static inline void konicawc_camera_off(struct uvd *uvd)
-{
-        DEBUG(0, "camera off");
-        konicawc_set_misc(uvd, 0x2, 0, 0x0b);
-}
-
-
-static void konicawc_set_camera_size(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
-       cam->width = camera_sizes[cam->size].width;
-       cam->height = camera_sizes[cam->size].height;
-       cam->yplanesz = cam->height * cam->width;
-       cam->cur_frame_size = (cam->yplanesz * 3) / 2;
-       cam->maxline = cam->yplanesz / 256;
-       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-}
-
-
-static int konicawc_setup_on_open(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
-           cam->brightness * 11);
-       konicawc_set_value(uvd, cam->brightness, SetBrightness);
-       DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
-           cam->white_bal * 11);
-       konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
-       DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
-           cam->contrast * 11);
-       konicawc_set_value(uvd, cam->contrast, SetContrast);
-       DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
-           cam->saturation * 11);
-       konicawc_set_value(uvd, cam->saturation, SetSaturation);
-       DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
-           cam->sharpness * 11);
-       konicawc_set_value(uvd, cam->sharpness, SetSharpness);
-       konicawc_set_camera_size(uvd);
-       cam->lastframe = -2;
-       cam->buttonsts = 0;
-       return 0;
-}
-
-
-static void konicawc_adjust_picture(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       konicawc_camera_off(uvd);
-       DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
-       uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
-       if(cam->brightness != uvd->vpic.brightness / 11) {
-          cam->brightness = uvd->vpic.brightness / 11;
-          DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
-              cam->brightness * 11);
-          konicawc_set_value(uvd, cam->brightness, SetBrightness);
-       }
-
-       DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
-       uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
-       if(cam->contrast != uvd->vpic.contrast / 11) {
-               cam->contrast = uvd->vpic.contrast / 11;
-               DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
-                   cam->contrast * 11);
-               konicawc_set_value(uvd, cam->contrast, SetContrast);
-       }
-       konicawc_camera_on(uvd);
-}
-
-#ifdef CONFIG_INPUT
-
-static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
-{
-       struct input_dev *input_dev;
-
-       usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
-       strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
-       cam->input = input_dev = input_allocate_device();
-       if (!input_dev) {
-               warn("Not enough memory for camera's input device\n");
-               return;
-       }
-
-       input_dev->name = "Konicawc snapshot button";
-       input_dev->phys = cam->input_physname;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &dev->dev;
-
-       input_dev->evbit[0] = BIT(EV_KEY);
-       input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
-
-       input_dev->private = cam;
-
-       input_register_device(cam->input);
-}
-
-static void konicawc_unregister_input(struct konicawc *cam)
-{
-       if (cam->input) {
-               input_unregister_device(cam->input);
-               cam->input = NULL;
-       }
-}
-
-static void konicawc_report_buttonstat(struct konicawc *cam)
-{
-       if (cam->input) {
-               input_report_key(cam->input, BTN_0, cam->buttonsts);
-               input_sync(cam->input);
-       }
-}
-
-#else
-
-static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }
-static inline void konicawc_unregister_input(struct konicawc *cam) { }
-static inline void konicawc_report_buttonstat(struct konicawc *cam) { }
-
-#endif /* CONFIG_INPUT */
-
-static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
-{
-       char *cdata;
-       int i, totlen = 0;
-       unsigned char *status = stsurb->transfer_buffer;
-       int keep = 0, discard = 0, bad = 0;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       for (i = 0; i < dataurb->number_of_packets; i++) {
-               int button = cam->buttonsts;
-               unsigned char sts;
-               int n = dataurb->iso_frame_desc[i].actual_length;
-               int st = dataurb->iso_frame_desc[i].status;
-               cdata = dataurb->transfer_buffer +
-                       dataurb->iso_frame_desc[i].offset;
-
-               /* Detect and ignore errored packets */
-               if (st < 0) {
-                       DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
-                             i, n, st);
-                       uvd->stats.iso_err_count++;
-                       continue;
-               }
-
-               /* Detect and ignore empty packets */
-               if (n <= 0) {
-                       uvd->stats.iso_skip_count++;
-                       continue;
-               }
-
-               /* See what the status data said about the packet */
-               sts = *(status+stsurb->iso_frame_desc[i].offset);
-
-               /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
-                * otherwise:
-                * bit 0 0: keep packet
-                *       1: drop packet (padding data)
-                *
-                * bit 4 0 button not clicked
-                *       1 button clicked
-                * button is used to `take a picture' (in software)
-                */
-
-               if(sts < 0x80) {
-                       button = !!(sts & 0x40);
-                       sts &= ~0x40;
-               }
-               
-               /* work out the button status, but don't do
-                  anything with it for now */
-
-               if(button != cam->buttonsts) {
-                       DEBUG(2, "button: %sclicked", button ? "" : "un");
-                       cam->buttonsts = button;
-                       konicawc_report_buttonstat(cam);
-               }
-
-               if(sts == 0x01) { /* drop frame */
-                       discard++;
-                       continue;
-               }
-               
-               if((sts > 0x01) && (sts < 0x80)) {
-                       info("unknown status %2.2x", sts);
-                       bad++;
-                       continue;
-               }
-               if(!sts && cam->lastframe == -2) {
-                       DEBUG(2, "dropping frame looking for image start");
-                       continue;
-               }
-
-               keep++;
-               if(sts & 0x80) { /* frame start */
-                       unsigned char marker[] = { 0, 0xff, 0, 0x00 };
-
-                       if(cam->lastframe == -2) {
-                               DEBUG(2, "found initial image");
-                               cam->lastframe = -1;
-                       }
-                               
-                       marker[3] = sts & 0x7F;
-                       RingQueue_Enqueue(&uvd->dp, marker, 4);
-                       totlen += 4;
-               }
-
-               totlen += n;    /* Little local accounting */
-               RingQueue_Enqueue(&uvd->dp, cdata, n);
-       }
-       DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
-                   keep, discard, bad, totlen);
-       return totlen;
-}
-
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
-        int i, ret;
-        for (i = 0; i < FRAMES_PER_DESC; i++) {
-                urb->iso_frame_desc[i].status = 0;
-        }
-        urb->dev = uvd->dev;
-        urb->status = 0;
-       ret = usb_submit_urb(urb, GFP_ATOMIC);
-       DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
-        if(ret)
-                err("usb_submit_urb error (%d)", ret);
-
-}
-
-
-static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct uvd *uvd = urb->context;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       /* We don't want to do anything if we are about to be removed! */
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-
-       if (!uvd->streaming) {
-               DEBUG(1, "Not streaming, but interrupt!");
-               return;
-       }
-
-       DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
-
-       uvd->stats.urb_count++;
-
-       if (urb->transfer_buffer_length > 32) {
-               cam->last_data_urb = urb;
-               return;
-       }
-       /* Copy the data received into ring queue */
-       if(cam->last_data_urb) {
-               int len = 0;
-               if(urb->start_frame != cam->last_data_urb->start_frame)
-                       err("Lost sync on frames");
-               else if (!urb->status && !cam->last_data_urb->status)
-                       len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
-
-               resubmit_urb(uvd, cam->last_data_urb);
-               resubmit_urb(uvd, urb);
-               cam->last_data_urb = NULL;
-               uvd->stats.urb_length = len;
-               uvd->stats.data_count += len;
-               if(len)
-                       RingQueue_WakeUpInterruptible(&uvd->dp);
-               return;
-       }
-       return;
-}
-
-
-static int konicawc_start_data(struct uvd *uvd)
-{
-       struct usb_device *dev = uvd->dev;
-       int i, errFlag;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       int pktsz;
-       struct usb_interface *intf;
-       struct usb_host_interface *interface = NULL;
-
-       intf = usb_ifnum_to_if(dev, uvd->iface);
-       if (intf)
-               interface = usb_altnum_to_altsetting(intf,
-                               spd_to_iface[cam->speed]);
-       if (!interface)
-               return -ENXIO;
-       pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize);
-       DEBUG(1, "pktsz = %d", pktsz);
-       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-               err("Camera is not operational");
-               return -EFAULT;
-       }
-       uvd->curframe = -1;
-       konicawc_camera_on(uvd);
-       /* Alternate interface 1 is is the biggest frame size */
-       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
-       if (i < 0) {
-               err("usb_set_interface error");
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-
-       /* We double buffer the Iso lists */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               int j, k;
-               struct urb *urb = uvd->sbuf[i].urb;
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = uvd->sbuf[i].data;
-               urb->complete = konicawc_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
-               for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = pktsz;
-               }
-
-               urb = cam->sts_urb[i];
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = cam->sts_buf[i];
-               urb->complete = konicawc_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = FRAMES_PER_DESC;
-               for (j=0; j < FRAMES_PER_DESC; j++) {
-                       urb->iso_frame_desc[j].offset = j;
-                       urb->iso_frame_desc[j].length = 1;
-               }
-       }
-
-       cam->last_data_urb = NULL;
-       
-       /* Submit all URBs */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
-               if (errFlag)
-                       err("usb_submit_isoc(%d) ret %d", i, errFlag);
-
-               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-               if (errFlag)
-                       err ("usb_submit_isoc(%d) ret %d", i, errFlag);
-       }
-
-       uvd->streaming = 1;
-       DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
-       return 0;
-}
-
-
-static void konicawc_stop_data(struct uvd *uvd)
-{
-       int i, j;
-       struct konicawc *cam;
-
-       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-               return;
-
-       konicawc_camera_off(uvd);
-       uvd->streaming = 0;
-       cam = (struct konicawc *)uvd->user_data;
-       cam->last_data_urb = NULL;
-
-       /* Unschedule all of the iso td's */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               usb_kill_urb(uvd->sbuf[i].urb);
-               usb_kill_urb(cam->sts_urb[i]);
-       }
-
-       if (!uvd->remove_pending) {
-               /* Set packet size to 0 */
-               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
-               if (j < 0) {
-                       err("usb_set_interface() error %d.", j);
-                       uvd->last_error = j;
-               }
-       }
-}
-
-
-static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{      
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       int maxline = cam->maxline;
-       int yplanesz = cam->yplanesz;
-
-       assert(frame != NULL);
-
-       DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
-       DEBUG(3, "Frame state = %d", frame->scanstate);
-
-       if(frame->scanstate == ScanState_Scanning) {
-               int drop = 0;
-               int curframe;
-               int fdrops = 0;
-               DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
-               while(RingQueue_GetLength(&uvd->dp) >= 4) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
-                               curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
-                               if(cam->lastframe >= 0) {
-                                       fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
-                                       fdrops--;
-                                       if(fdrops) {
-                                               info("Dropped %d frames (%d -> %d)", fdrops,
-                                                    cam->lastframe, curframe);
-                                       }
-                               }
-                               cam->lastframe = curframe;
-                               frame->curline = 0;
-                               frame->scanstate = ScanState_Lines;
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
-                               break;
-                       }
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-                       drop++;
-               }
-               if(drop)
-                       DEBUG(2, "dropped %d bytes looking for new frame", drop);
-       }
-
-       if(frame->scanstate == ScanState_Scanning)
-               return;
-               
-       /* Try to move data from queue into frame buffer
-        * We get data in blocks of 384 bytes made up of:
-        * 256 Y, 64 U, 64 V.
-        * This needs to be written out as a Y plane, a U plane and a V plane.
-        */
-               
-       while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
-               /* Y */
-               RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
-               /* U */
-               RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
-               /* V */
-               RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
-               frame->seqRead_Length += 384;
-               frame->curline++;
-       }
-       /* See if we filled the frame */
-       if (frame->curline == maxline) {
-               DEBUG(5, "got whole frame");
-
-               frame->frameState = FrameState_Done_Hold;
-               frame->curline = 0;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-
-static int konicawc_find_fps(int size, int fps)
-{
-       int i;
-
-       fps *= 3;
-       DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
-       if(fps <= spd_to_fps[size][0])
-               return 0;
-
-       if(fps >= spd_to_fps[size][MAX_SPEED])
-               return MAX_SPEED;
-
-       for(i = 0; i < MAX_SPEED; i++) {
-               if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
-                       DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
-                       if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
-                               return i;
-                       else
-                               return i+1;
-               }
-       }
-       return MAX_SPEED+1;
-}
-
-
-static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       int newspeed = cam->speed;
-       int newsize;
-       int x = vw->width;
-       int y = vw->height;
-       int fps = vw->flags;
-
-       if(x > 0 && y > 0) {
-               DEBUG(2, "trying to find size %d,%d", x, y);
-               for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
-                       if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
-                               break;
-               }
-       } else {
-               newsize = cam->size;
-       }
-
-       if(newsize > MAX_FRAME_SIZE) {
-               DEBUG(1, "couldn't find size %d,%d", x, y);
-               return -EINVAL;
-       }
-
-       if(fps > 0) {
-               DEBUG(1, "trying to set fps to %d", fps);
-               newspeed = konicawc_find_fps(newsize, fps);
-               DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
-       }
-
-       if(newspeed > MAX_SPEED)
-               return -EINVAL;
-
-       DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
-       if((newsize == cam->size) && (newspeed == cam->speed)) {
-               DEBUG(1, "Nothing to do");
-               return 0;
-       }
-       DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
-            camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
-
-       konicawc_stop_data(uvd);
-       uvd->ifaceAltActive = spd_to_iface[newspeed];
-       DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
-       cam->speed = newspeed;
-
-       if(cam->size != newsize) {
-               cam->size = newsize;
-               konicawc_set_camera_size(uvd);
-       }
-
-       /* Flush the input queue and clear any current frame in progress */
-
-       RingQueue_Flush(&uvd->dp);
-       cam->lastframe = -2;
-       if(uvd->curframe != -1) {
-               uvd->frame[uvd->curframe].curline = 0;
-               uvd->frame[uvd->curframe].seqRead_Length = 0;
-               uvd->frame[uvd->curframe].seqRead_Index = 0;
-       }
-
-       konicawc_start_data(uvd);
-       return 0;
-}
-
-
-static int konicawc_calculate_fps(struct uvd *uvd)
-{
-       struct konicawc *cam = uvd->user_data;
-       return spd_to_fps[cam->size][cam->speed]/3;
-}
-
-
-static void konicawc_configure_video(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       u8 buf[2];
-
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
-       RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
-       RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
-       RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
-       RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
-
-       cam->brightness = brightness / 11;
-       cam->contrast = contrast / 11;
-       cam->saturation = saturation / 11;
-       cam->sharpness = sharpness / 11;
-       cam->white_bal = whitebal / 11;
-
-       uvd->vpic.colour = 108;
-       uvd->vpic.hue = 108;
-       uvd->vpic.brightness = brightness;
-       uvd->vpic.contrast = contrast;
-       uvd->vpic.whiteness = whitebal;
-       uvd->vpic.depth = 6;
-       uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "Konica Webcam");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-       uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
-       uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
-       uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
-       uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0 ;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-
-       /* Talk to device */
-       DEBUG(1, "device init");
-       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
-               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
-       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
-               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
-       if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
-               DEBUG(2, "2,0,d failed");
-       DEBUG(1, "setting initial values");
-}
-
-static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct uvd *uvd = NULL;
-       int ix, i, nas;
-       int actInterface=-1, inactInterface=-1, maxPS=0;
-       unsigned char video_ep = 0;
-
-       DEBUG(1, "konicawc_probe(%p)", intf);
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice));
-       RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
-
-       /* Validate found interface: must have one ISO endpoint */
-       nas = intf->num_altsetting;
-       if (nas != 8) {
-               err("Incorrect number of alternate settings (%d) for this camera!", nas);
-               return -ENODEV;
-       }
-       /* Validate all alternate settings */
-       for (ix=0; ix < nas; ix++) {
-               const struct usb_host_interface *interface;
-               const struct usb_endpoint_descriptor *endpoint;
-
-               interface = &intf->altsetting[ix];
-               i = interface->desc.bAlternateSetting;
-               if (interface->desc.bNumEndpoints != 2) {
-                       err("Interface %d. has %u. endpoints!",
-                           interface->desc.bInterfaceNumber,
-                           (unsigned)(interface->desc.bNumEndpoints));
-                       return -ENODEV;
-               }
-               endpoint = &interface->endpoint[1].desc;
-               DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
-                   endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize));
-               if (video_ep == 0)
-                       video_ep = endpoint->bEndpointAddress;
-               else if (video_ep != endpoint->bEndpointAddress) {
-                       err("Alternate settings have different endpoint addresses!");
-                       return -ENODEV;
-               }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
-                       err("Interface %d. has non-ISO endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
-                       err("Interface %d. has ISO OUT endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
-                       if (inactInterface < 0)
-                               inactInterface = i;
-                       else {
-                               err("More than one inactive alt. setting!");
-                               return -ENODEV;
-                       }
-               } else {
-                       if (i == spd_to_iface[speed]) {
-                               /* This one is the requested one */
-                               actInterface = i;
-                       }
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS)
-                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-       }
-       if(actInterface == -1) {
-               err("Cant find required endpoint");
-               return -ENODEV;
-       }
-
-       DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (uvd != NULL) {
-               struct konicawc *cam = (struct konicawc *)(uvd->user_data);
-               /* Here uvd is a fully allocated uvd object */
-               for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
-                       cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-                       if(cam->sts_urb[i] == NULL) {
-                               while(i--) {
-                                       usb_free_urb(cam->sts_urb[i]);
-                               }
-                               err("can't allocate urbs");
-                               return -ENOMEM;
-                       }
-               }
-               cam->speed = speed;
-               RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
-               cam->width = camera_sizes[size].width;
-               cam->height = camera_sizes[size].height;
-               cam->size = size;
-
-               uvd->flags = 0;
-               uvd->debug = debug;
-               uvd->dev = dev;
-               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
-               uvd->ifaceAltInactive = inactInterface;
-               uvd->ifaceAltActive = actInterface;
-               uvd->video_endp = video_ep;
-               uvd->iso_packet_len = maxPS;
-               uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
-               uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
-               uvd->canvas = VIDEOSIZE(320, 240);
-               uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
-               /* Initialize konicawc specific data */
-               konicawc_configure_video(uvd);
-
-               i = usbvideo_RegisterVideoDevice(uvd);
-               uvd->max_frame_size = (320 * 240 * 3)/2;
-               if (i != 0) {
-                       err("usbvideo_RegisterVideoDevice() failed.");
-                       uvd = NULL;
-               }
-
-               konicawc_register_input(cam, dev);
-       }
-
-       if (uvd) {
-               usb_set_intfdata (intf, uvd);
-               return 0;
-       }
-       return -EIO;
-}
-
-
-static void konicawc_free_uvd(struct uvd *uvd)
-{
-       int i;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       konicawc_unregister_input(cam);
-
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-               usb_free_urb(cam->sts_urb[i]);
-               cam->sts_urb[i] = NULL;
-       }
-}
-
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
-       { }  /* Terminating entry */
-};
-
-
-static int __init konicawc_init(void)
-{
-       struct usbvideo_cb cbTbl;
-       info(DRIVER_DESC " " DRIVER_VERSION);
-       memset(&cbTbl, 0, sizeof(cbTbl));
-       cbTbl.probe = konicawc_probe;
-       cbTbl.setupOnOpen = konicawc_setup_on_open;
-       cbTbl.processData = konicawc_process_isoc;
-       cbTbl.getFPS = konicawc_calculate_fps;
-       cbTbl.setVideoMode = konicawc_set_video_mode;
-       cbTbl.startDataPump = konicawc_start_data;
-       cbTbl.stopDataPump = konicawc_stop_data;
-       cbTbl.adjustPicture = konicawc_adjust_picture;
-       cbTbl.userFree = konicawc_free_uvd;
-       return usbvideo_register(
-               &cams,
-               MAX_CAMERAS,
-               sizeof(struct konicawc),
-               "konicawc",
-               &cbTbl,
-               THIS_MODULE,
-               id_table);
-}
-
-
-static void __exit konicawc_cleanup(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-module_param(speed, int, 0);
-MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
-module_param(saturation, int, 0);
-MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
-module_param(whitebal, int, 0);
-MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(konicawc_init);
-module_exit(konicawc_cleanup);
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
deleted file mode 100644 (file)
index da44579..0000000
+++ /dev/null
@@ -1,5932 +0,0 @@
-/*
- * OmniVision OV511 Camera-to-USB Bridge Driver
- *
- * Copyright (c) 1999-2003 Mark W. McClelland
- * Original decompression code Copyright 1998-2000 OmniVision Technologies
- * Many improvements by Bret Wallach <bwallac1@san.rr.com>
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- * Snapshot code by Kevin Moore
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka <claudio@conectiva.com>
- * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * URB error messages from pwc driver by Nemosoft
- * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
- * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
- *
- * Based on the Linux CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt.
- * 
- * Please see the file: Documentation/usb/ov511.txt
- * and the website at:  http://alpha.dyndns.org/ov511
- * for more info.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <asm/semaphore.h>
-#include <asm/processor.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#if defined (__i386__)
-       #include <asm/cpufeature.h>
-#endif
-
-#include "ov511.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.64 for Linux 2.5"
-#define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-       & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-       <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "ov511 USB Camera Driver"
-
-#define OV511_I2C_RETRIES 3
-#define ENABLE_Y_QUANTABLE 1
-#define ENABLE_UV_QUANTABLE 1
-
-#define OV511_MAX_UNIT_VIDEO 16
-
-/* Pixel count * bytes per YUV420 pixel (1.5) */
-#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
-
-#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
-
-/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
-#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
-
-#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
-/**********************************************************************
- * Module Parameters
- * (See ov511.txt for detailed descriptions of these)
- **********************************************************************/
-
-/* These variables (and all static globals) default to zero */
-static int autobright          = 1;
-static int autogain            = 1;
-static int autoexp             = 1;
-static int debug;
-static int snapshot;
-static int cams                        = 1;
-static int compress;
-static int testpat;
-static int dumppix;
-static int led                         = 1;
-static int dump_bridge;
-static int dump_sensor;
-static int printph;
-static int phy                 = 0x1f;
-static int phuv                        = 0x05;
-static int pvy                 = 0x06;
-static int pvuv                        = 0x06;
-static int qhy                 = 0x14;
-static int qhuv                        = 0x03;
-static int qvy                 = 0x04;
-static int qvuv                        = 0x04;
-static int lightfreq;
-static int bandingfilter;
-static int clockdiv            = -1;
-static int packetsize          = -1;
-static int framedrop           = -1;
-static int fastset;
-static int force_palette;
-static int backlight;
-static int unit_video[OV511_MAX_UNIT_VIDEO];
-static int remove_zeros;
-static int mirror;
-static int ov518_color;
-
-module_param(autobright, int, 0);
-MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
-module_param(autogain, int, 0);
-MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
-module_param(autoexp, int, 0);
-MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
-  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
-module_param(snapshot, int, 0);
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
-module_param(cams, int, 0);
-MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
-module_param(compress, int, 0);
-MODULE_PARM_DESC(compress, "Turn on compression");
-module_param(testpat, int, 0);
-MODULE_PARM_DESC(testpat,
-  "Replace image with vertical bar testpattern (only partially working)");
-module_param(dumppix, int, 0);
-MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
-module_param(led, int, 0);
-MODULE_PARM_DESC(led,
-  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
-module_param(dump_bridge, int, 0);
-MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
-module_param(dump_sensor, int, 0);
-MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
-module_param(printph, int, 0);
-MODULE_PARM_DESC(printph, "Print frame start/end headers");
-module_param(phy, int, 0);
-MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
-module_param(phuv, int, 0);
-MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
-module_param(pvy, int, 0);
-MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
-module_param(pvuv, int, 0);
-MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
-module_param(qhy, int, 0);
-MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
-module_param(qhuv, int, 0);
-MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
-module_param(qvy, int, 0);
-MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
-module_param(qvuv, int, 0);
-MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
-module_param(lightfreq, int, 0);
-MODULE_PARM_DESC(lightfreq,
-  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
-module_param(bandingfilter, int, 0);
-MODULE_PARM_DESC(bandingfilter,
-  "Enable banding filter (to reduce effects of fluorescent lighting)");
-module_param(clockdiv, int, 0);
-MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
-module_param(packetsize, int, 0);
-MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
-module_param(framedrop, int, 0);
-MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
-module_param(fastset, int, 0);
-MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
-module_param(force_palette, int, 0);
-MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-module_param(backlight, int, 0);
-MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static int num_uv;
-module_param_array(unit_video, int, &num_uv, 0);
-MODULE_PARM_DESC(unit_video,
-  "Force use of specific minor number(s). 0 is not allowed.");
-module_param(remove_zeros, int, 0);
-MODULE_PARM_DESC(remove_zeros,
-  "Remove zero-padding from uncompressed incoming data");
-module_param(mirror, int, 0);
-MODULE_PARM_DESC(mirror, "Reverse image horizontally");
-module_param(ov518_color, int, 0);
-MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/**********************************************************************
- * Miscellaneous Globals
- **********************************************************************/
-
-static struct usb_driver ov511_driver;
-
-/* Number of times to retry a failed I2C transaction. Increase this if you
- * are getting "Failed to read sensor ID..." */
-static const int i2c_detect_tries = 5;
-
-static struct usb_device_id device_table [] = {
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
-       { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-       { }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
-
-/**********************************************************************
- * Symbolic Names
- **********************************************************************/
-
-/* Known OV511-based cameras */
-static struct symbolic_list camlist[] = {
-       {   0, "Generic Camera (no ID)" },
-       {   1, "Mustek WCam 3X" },
-       {   3, "D-Link DSB-C300" },
-       {   4, "Generic OV511/OV7610" },
-       {   5, "Puretek PT-6007" },
-       {   6, "Lifeview USB Life TV (NTSC)" },
-       {  21, "Creative Labs WebCam 3" },
-       {  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
-       {  36, "Koala-Cam" },
-       {  38, "Lifeview USB Life TV (PAL)" },
-       {  41, "Samsung Anycam MPC-M10" },
-       {  43, "Mtekvision Zeca MV402" },
-       {  46, "Suma eON" },
-       {  70, "Lifeview USB Life TV (PAL/SECAM)" },
-       { 100, "Lifeview RoboCam" },
-       { 102, "AverMedia InterCam Elite" },
-       { 112, "MediaForte MV300" },    /* or OV7110 evaluation kit */
-       { 134, "Ezonics EZCam II" },
-       { 192, "Webeye 2000B" },
-       { 253, "Alpha Vision Tech. AlphaCam SE" },
-       {  -1, NULL }
-};
-
-/* Video4Linux1 Palettes */
-static struct symbolic_list v4l1_plist[] = {
-       { VIDEO_PALETTE_GREY,   "GREY" },
-       { VIDEO_PALETTE_HI240,  "HI240" },
-       { VIDEO_PALETTE_RGB565, "RGB565" },
-       { VIDEO_PALETTE_RGB24,  "RGB24" },
-       { VIDEO_PALETTE_RGB32,  "RGB32" },
-       { VIDEO_PALETTE_RGB555, "RGB555" },
-       { VIDEO_PALETTE_YUV422, "YUV422" },
-       { VIDEO_PALETTE_YUYV,   "YUYV" },
-       { VIDEO_PALETTE_UYVY,   "UYVY" },
-       { VIDEO_PALETTE_YUV420, "YUV420" },
-       { VIDEO_PALETTE_YUV411, "YUV411" },
-       { VIDEO_PALETTE_RAW,    "RAW" },
-       { VIDEO_PALETTE_YUV422P,"YUV422P" },
-       { VIDEO_PALETTE_YUV411P,"YUV411P" },
-       { VIDEO_PALETTE_YUV420P,"YUV420P" },
-       { VIDEO_PALETTE_YUV410P,"YUV410P" },
-       { -1, NULL }
-};
-
-static struct symbolic_list brglist[] = {
-       { BRG_OV511,            "OV511" },
-       { BRG_OV511PLUS,        "OV511+" },
-       { BRG_OV518,            "OV518" },
-       { BRG_OV518PLUS,        "OV518+" },
-       { -1, NULL }
-};
-
-static struct symbolic_list senlist[] = {
-       { SEN_OV76BE,   "OV76BE" },
-       { SEN_OV7610,   "OV7610" },
-       { SEN_OV7620,   "OV7620" },
-       { SEN_OV7620AE, "OV7620AE" },
-       { SEN_OV6620,   "OV6620" },
-       { SEN_OV6630,   "OV6630" },
-       { SEN_OV6630AE, "OV6630AE" },
-       { SEN_OV6630AF, "OV6630AF" },
-       { SEN_OV8600,   "OV8600" },
-       { SEN_KS0127,   "KS0127" },
-       { SEN_KS0127B,  "KS0127B" },
-       { SEN_SAA7111A, "SAA7111A" },
-       { -1, NULL }
-};
-
-/* URB error codes: */
-static struct symbolic_list urb_errlist[] = {
-       { -ENOSR,       "Buffer error (overrun)" },
-       { -EPIPE,       "Stalled (device not responding)" },
-       { -EOVERFLOW,   "Babble (bad cable?)" },
-       { -EPROTO,      "Bit-stuff error (bad cable?)" },
-       { -EILSEQ,      "CRC/Timeout" },
-       { -ETIMEDOUT,   "NAK (device does not respond)" },
-       { -1, NULL }
-};
-
-/**********************************************************************
- * Memory management
- **********************************************************************/
-static void *
-rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void
-rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-/**********************************************************************
- *
- * Register I/O
- *
- **********************************************************************/
-
-/* Write an OV51x register */
-static int
-reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       mutex_lock(&ov->cbuf_lock);
-       ov->cbuf[0] = value;
-       rc = usb_control_msg(ov->dev,
-                            usb_sndctrlpipe(ov->dev, 0),
-                            (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
-                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-       mutex_unlock(&ov->cbuf_lock);
-
-       if (rc < 0)
-               err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
-
-       return rc;
-}
-
-/* Read from an OV51x register */
-/* returns: negative is error, pos or zero is data */
-static int
-reg_r(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->cbuf_lock);
-       rc = usb_control_msg(ov->dev,
-                            usb_rcvctrlpipe(ov->dev, 0),
-                            (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
-                            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-
-       if (rc < 0) {
-               err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
-       } else {
-               rc = ov->cbuf[0];
-               PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-       }
-
-       mutex_unlock(&ov->cbuf_lock);
-
-       return rc;
-}
-
-/*
- * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-reg_w_mask(struct usb_ov511 *ov,
-          unsigned char reg,
-          unsigned char value,
-          unsigned char mask)
-{
-       int ret;
-       unsigned char oldval, newval;
-
-       ret = reg_r(ov, reg);
-       if (ret < 0)
-               return ret;
-
-       oldval = (unsigned char) ret;
-       oldval &= (~mask);              /* Clear the masked bits */
-       value &= mask;                  /* Enforce mask on value */
-       newval = oldval | value;        /* Set the desired bits */
-
-       return (reg_w(ov, reg, newval));
-}
-
-/* 
- * Writes multiple (n) byte value to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce).
- */
-static int
-ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
-
-       mutex_lock(&ov->cbuf_lock);
-
-       *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
-
-       rc = usb_control_msg(ov->dev,
-                            usb_sndctrlpipe(ov->dev, 0),
-                            1 /* REG_IO */,
-                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, ov->cbuf, n, 1000);
-       mutex_unlock(&ov->cbuf_lock);
-
-       if (rc < 0)
-               err("reg write multiple: error %d: %s", rc,
-                   symbolic(urb_errlist, rc));
-
-       return rc;
-}
-
-static int
-ov511_upload_quan_tables(struct usb_ov511 *ov)
-{
-       unsigned char *pYTable = yQuanTable511;
-       unsigned char *pUVTable = uvQuanTable511;
-       unsigned char val0, val1;
-       int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-       PDEBUG(4, "Uploading quantization tables");
-
-       for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
-               if (ENABLE_Y_QUANTABLE) {
-                       val0 = *pYTable++;
-                       val1 = *pYTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               if (ENABLE_UV_QUANTABLE) {
-                       val0 = *pUVTable++;
-                       val1 = *pUVTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               reg++;
-       }
-
-       return 0;
-}
-
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
-ov518_upload_quan_tables(struct usb_ov511 *ov)
-{
-       unsigned char *pYTable = yQuanTable518;
-       unsigned char *pUVTable = uvQuanTable518;
-       unsigned char val0, val1;
-       int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-       PDEBUG(4, "Uploading quantization tables");
-
-       for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
-               if (ENABLE_Y_QUANTABLE) {
-                       val0 = *pYTable++;
-                       val1 = *pYTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               if (ENABLE_UV_QUANTABLE) {
-                       val0 = *pUVTable++;
-                       val1 = *pUVTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               reg++;
-       }
-
-       return 0;
-}
-
-static int
-ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
-{
-       int rc;
-
-       /* Setting bit 0 not allowed on 518/518Plus */
-       if (ov->bclass == BCL_OV518)
-               reset_type &= 0xfe;
-
-       PDEBUG(4, "Reset: type=0x%02X", reset_type);
-
-       rc = reg_w(ov, R51x_SYS_RESET, reset_type);
-       rc = reg_w(ov, R51x_SYS_RESET, 0);
-
-       if (rc < 0)
-               err("reset: command failed");
-
-       return rc;
-}
-
-/**********************************************************************
- *
- * Low-level I2C I/O functions
- *
- **********************************************************************/
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_w(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_write_internal(struct usb_ov511 *ov,
-                        unsigned char reg,
-                        unsigned char value)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* Select camera register */
-       rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-       if (rc < 0)
-               return rc;
-
-       /* Write "value" to I2C data port of OV511 */
-       rc = reg_w(ov, R51x_I2C_DATA, value);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 3-byte write cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x01);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/* NOTE: Do not call this function directly! */
-static int
-ov511_i2c_write_internal(struct usb_ov511 *ov,
-                        unsigned char reg,
-                        unsigned char value)
-{
-       int rc, retries;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* Three byte write cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Select camera register */
-               rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-               if (rc < 0)
-                       break;
-
-               /* Write "value" to I2C data port of OV511 */
-               rc = reg_w(ov, R51x_I2C_DATA, value);
-               if (rc < 0)
-                       break;
-
-               /* Initiate 3-byte write cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x01);
-               if (rc < 0)
-                       break;
-
-               /* Retry until idle */
-               do
-                       rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0)); 
-               if (rc < 0)
-                       break;
-
-               /* Ack? */
-               if ((rc&2) == 0) {
-                       rc = 0;
-                       break;
-               }
-#if 0
-               /* I2C abort */
-               reg_w(ov, R511_I2C_CTL, 0x10);
-#endif
-               if (--retries < 0) {
-                       err("i2c write retries exhausted");
-                       rc = -1;
-                       break;
-               }
-       }
-
-       return rc;
-}
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_r(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc, value;
-
-       /* Select camera register */
-       rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 2-byte write cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x03);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 2-byte read cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x05);
-       if (rc < 0)
-               return rc;
-
-       value = reg_r(ov, R51x_I2C_DATA);
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       return value;
-}
-
-/* NOTE: Do not call this function directly!
- * returns: negative is error, pos or zero is data */
-static int
-ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc, value, retries;
-
-       /* Two byte write cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Select camera register */
-               rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-               if (rc < 0)
-                       return rc;
-
-               /* Initiate 2-byte write cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x03);
-               if (rc < 0)
-                       return rc;
-
-               /* Retry until idle */
-               do
-                        rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
-               if (rc < 0)
-                       return rc;
-
-               if ((rc&2) == 0) /* Ack? */
-                       break;
-
-               /* I2C abort */
-               reg_w(ov, R511_I2C_CTL, 0x10);
-
-               if (--retries < 0) {
-                       err("i2c write retries exhausted");
-                       return -1;
-               }
-       }
-
-       /* Two byte read cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Initiate 2-byte read cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x05);
-               if (rc < 0)
-                       return rc;
-
-               /* Retry until idle */
-               do
-                       rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
-               if (rc < 0)
-                       return rc;
-
-               if ((rc&2) == 0) /* Ack? */
-                       break;
-
-               /* I2C abort */
-               rc = reg_w(ov, R511_I2C_CTL, 0x10);
-               if (rc < 0)
-                       return rc;
-
-               if (--retries < 0) {
-                       err("i2c read retries exhausted");
-                       return -1;
-               }
-       }
-
-       value = reg_r(ov, R51x_I2C_DATA);
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* This is needed to make i2c_w() work */
-       rc = reg_w(ov, R511_I2C_CTL, 0x05);
-       if (rc < 0)
-               return rc;
-
-       return value;
-}
-
-/* returns: negative is error, pos or zero is data */
-static int
-i2c_r(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_read_internal(ov, reg);
-       else
-               rc = ov511_i2c_read_internal(ov, reg);
-
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-static int
-i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_write_internal(ov, reg, value);
-       else
-               rc = ov511_i2c_write_internal(ov, reg, value);
-
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
-                             unsigned char reg,
-                             unsigned char value,
-                             unsigned char mask)
-{
-       int rc;
-       unsigned char oldval, newval;
-
-       if (mask == 0xff) {
-               newval = value;
-       } else {
-               if (ov->bclass == BCL_OV518)
-                       rc = ov518_i2c_read_internal(ov, reg);
-               else
-                       rc = ov511_i2c_read_internal(ov, reg);
-               if (rc < 0)
-                       return rc;
-
-               oldval = (unsigned char) rc;
-               oldval &= (~mask);              /* Clear the masked bits */
-               value &= mask;                  /* Enforce mask on value */
-               newval = oldval | value;        /* Set the desired bits */
-       }
-
-       if (ov->bclass == BCL_OV518)
-               return (ov518_i2c_write_internal(ov, reg, newval));
-       else
-               return (ov511_i2c_write_internal(ov, reg, newval));
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-i2c_w_mask(struct usb_ov511 *ov,
-          unsigned char reg,
-          unsigned char value,
-          unsigned char mask)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-/* Set the read and write slave IDs. The "slave" argument is the write slave,
- * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
- * when calling this. This should not be called from outside the i2c I/O
- * functions.
- */
-static int
-i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
-{
-       int rc;
-
-       rc = reg_w(ov, R51x_I2C_W_SID, slave);
-       if (rc < 0)
-               return rc;
-
-       rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
-i2c_w_slave(struct usb_ov511 *ov,
-           unsigned char slave,
-           unsigned char reg,
-           unsigned char value,
-           unsigned char mask)
-{
-       int rc = 0;
-
-       mutex_lock(&ov->i2c_lock);
-
-       /* Set new slave IDs */
-       rc = i2c_set_slave_internal(ov, slave);
-       if (rc < 0)
-               goto out;
-
-       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-
-out:
-       /* Restore primary IDs */
-       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-               err("Couldn't restore primary I2C slave");
-
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-/* Read from a specific I2C slave ID and register */
-static int
-i2c_r_slave(struct usb_ov511 *ov,
-           unsigned char slave,
-           unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       /* Set new slave IDs */
-       rc = i2c_set_slave_internal(ov, slave);
-       if (rc < 0)
-               goto out;
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_read_internal(ov, reg);
-       else
-               rc = ov511_i2c_read_internal(ov, reg);
-
-out:
-       /* Restore primary IDs */
-       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-               err("Couldn't restore primary I2C slave");
-
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
-ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       rc = i2c_set_slave_internal(ov, sid);
-       if (rc < 0)
-               goto out;
-
-       // FIXME: Is this actually necessary?
-       rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-out:
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-static int
-write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
-{
-       int rc;
-
-       while (pRegvals->bus != OV511_DONE_BUS) {
-               if (pRegvals->bus == OV511_REG_BUS) {
-                       if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-                               return rc;
-               } else if (pRegvals->bus == OV511_I2C_BUS) {
-                       if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-                               return rc;
-               } else {
-                       err("Bad regval array");
-                       return -1;
-               }
-               pRegvals++;
-       }
-       return 0;
-}
-
-#ifdef OV511_DEBUG
-static void
-dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-       int i, rc;
-
-       for (i = reg1; i <= regn; i++) {
-               rc = i2c_r(ov, i);
-               info("Sensor[0x%02X] = 0x%02X", i, rc);
-       }
-}
-
-static void
-dump_i2c_regs(struct usb_ov511 *ov)
-{
-       info("I2C REGS");
-       dump_i2c_range(ov, 0x00, 0x7C);
-}
-
-static void
-dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-       int i, rc;
-
-       for (i = reg1; i <= regn; i++) {
-               rc = reg_r(ov, i);
-               info("OV511[0x%02X] = 0x%02X", i, rc);
-       }
-}
-
-static void
-ov511_dump_regs(struct usb_ov511 *ov)
-{
-       info("CAMERA INTERFACE REGS");
-       dump_reg_range(ov, 0x10, 0x1f);
-       info("DRAM INTERFACE REGS");
-       dump_reg_range(ov, 0x20, 0x23);
-       info("ISO FIFO REGS");
-       dump_reg_range(ov, 0x30, 0x31);
-       info("PIO REGS");
-       dump_reg_range(ov, 0x38, 0x39);
-       dump_reg_range(ov, 0x3e, 0x3e);
-       info("I2C REGS");
-       dump_reg_range(ov, 0x40, 0x49);
-       info("SYSTEM CONTROL REGS");
-       dump_reg_range(ov, 0x50, 0x55);
-       dump_reg_range(ov, 0x5e, 0x5f);
-       info("OmniCE REGS");
-       dump_reg_range(ov, 0x70, 0x79);
-       /* NOTE: Quantization tables are not readable. You will get the value
-        * in reg. 0x79 for every table register */
-       dump_reg_range(ov, 0x80, 0x9f);
-       dump_reg_range(ov, 0xa0, 0xbf);
-
-}
-
-static void
-ov518_dump_regs(struct usb_ov511 *ov)
-{
-       info("VIDEO MODE REGS");
-       dump_reg_range(ov, 0x20, 0x2f);
-       info("DATA PUMP AND SNAPSHOT REGS");
-       dump_reg_range(ov, 0x30, 0x3f);
-       info("I2C REGS");
-       dump_reg_range(ov, 0x40, 0x4f);
-       info("SYSTEM CONTROL AND VENDOR REGS");
-       dump_reg_range(ov, 0x50, 0x5f);
-       info("60 - 6F");
-       dump_reg_range(ov, 0x60, 0x6f);
-       info("70 - 7F");
-       dump_reg_range(ov, 0x70, 0x7f);
-       info("Y QUANTIZATION TABLE");
-       dump_reg_range(ov, 0x80, 0x8f);
-       info("UV QUANTIZATION TABLE");
-       dump_reg_range(ov, 0x90, 0x9f);
-       info("A0 - BF");
-       dump_reg_range(ov, 0xa0, 0xbf);
-       info("CBR");
-       dump_reg_range(ov, 0xc0, 0xcf);
-}
-#endif
-
-/*****************************************************************************/
-
-/* Temporarily stops OV511 from functioning. Must do this before changing
- * registers while the camera is streaming */
-static inline int
-ov51x_stop(struct usb_ov511 *ov)
-{
-       PDEBUG(4, "stopping");
-       ov->stopped = 1;
-       if (ov->bclass == BCL_OV518)
-               return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
-       else
-               return (reg_w(ov, R51x_SYS_RESET, 0x3d));
-}
-
-/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
- * actually stopped (for performance). */
-static inline int
-ov51x_restart(struct usb_ov511 *ov)
-{
-       if (ov->stopped) {
-               PDEBUG(4, "restarting");
-               ov->stopped = 0;
-
-               /* Reinitialize the stream */
-               if (ov->bclass == BCL_OV518)
-                       reg_w(ov, 0x2f, 0x80);
-
-               return (reg_w(ov, R51x_SYS_RESET, 0x00));
-       }
-
-       return 0;
-}
-
-/* Sleeps until no frames are active. Returns !0 if got signal */
-static int
-ov51x_wait_frames_inactive(struct usb_ov511 *ov)
-{
-       return wait_event_interruptible(ov->wq, ov->curframe < 0);
-}
-
-/* Resets the hardware snapshot button */
-static void
-ov51x_clear_snapshot(struct usb_ov511 *ov)
-{
-       if (ov->bclass == BCL_OV511) {
-               reg_w(ov, R51x_SYS_SNAP, 0x00);
-               reg_w(ov, R51x_SYS_SNAP, 0x02);
-               reg_w(ov, R51x_SYS_SNAP, 0x00);
-       } else if (ov->bclass == BCL_OV518) {
-               warn("snapshot reset not supported yet on OV518(+)");
-       } else {
-               err("clear snap: invalid bridge type");
-       }
-}
-
-#if 0
-/* Checks the status of the snapshot button. Returns 1 if it was pressed since
- * it was last cleared, and zero in all other cases (including errors) */
-static int
-ov51x_check_snapshot(struct usb_ov511 *ov)
-{
-       int ret, status = 0;
-
-       if (ov->bclass == BCL_OV511) {
-               ret = reg_r(ov, R51x_SYS_SNAP);
-               if (ret < 0) {
-                       err("Error checking snspshot status (%d)", ret);
-               } else if (ret & 0x08) {
-                       status = 1;
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               warn("snapshot check not supported yet on OV518(+)");
-       } else {
-               err("check snap: invalid bridge type");
-       }
-
-       return status;
-}
-#endif
-
-/* This does an initial reset of an OmniVision sensor and ensures that I2C
- * is synchronized. Returns <0 for failure.
- */
-static int
-init_ov_sensor(struct usb_ov511 *ov)
-{
-       int i, success;
-
-       /* Reset the sensor */
-       if (i2c_w(ov, 0x12, 0x80) < 0)
-               return -EIO;
-
-       /* Wait for it to initialize */
-       msleep(150);
-
-       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
-               if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-                   (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-                       success = 1;
-                       continue;
-               }
-
-               /* Reset the sensor */
-               if (i2c_w(ov, 0x12, 0x80) < 0)
-                       return -EIO;
-               /* Wait for it to initialize */
-               msleep(150);
-               /* Dummy read to sync I2C */
-               if (i2c_r(ov, 0x00) < 0)
-                       return -EIO;
-       }
-
-       if (!success)
-               return -EIO;
-
-       PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
-       return 0;
-}
-
-static int
-ov511_set_packet_size(struct usb_ov511 *ov, int size)
-{
-       int alt, mult;
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       mult = size >> 5;
-
-       if (ov->bridge == BRG_OV511) {
-               if (size == 0)
-                       alt = OV511_ALT_SIZE_0;
-               else if (size == 257)
-                       alt = OV511_ALT_SIZE_257;
-               else if (size == 513)
-                       alt = OV511_ALT_SIZE_513;
-               else if (size == 769)
-                       alt = OV511_ALT_SIZE_769;
-               else if (size == 993)
-                       alt = OV511_ALT_SIZE_993;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (size == 0)
-                       alt = OV511PLUS_ALT_SIZE_0;
-               else if (size == 33)
-                       alt = OV511PLUS_ALT_SIZE_33;
-               else if (size == 129)
-                       alt = OV511PLUS_ALT_SIZE_129;
-               else if (size == 257)
-                       alt = OV511PLUS_ALT_SIZE_257;
-               else if (size == 385)
-                       alt = OV511PLUS_ALT_SIZE_385;
-               else if (size == 513)
-                       alt = OV511PLUS_ALT_SIZE_513;
-               else if (size == 769)
-                       alt = OV511PLUS_ALT_SIZE_769;
-               else if (size == 961)
-                       alt = OV511PLUS_ALT_SIZE_961;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else {
-               err("Set packet size: Invalid bridge type");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
-
-       if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
-               return -EIO;
-
-       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-               err("Set packet size: set interface error");
-               return -EBUSY;
-       }
-
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       ov->packet_size = size;
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
- * optional packet number byte. The actual size *is* stored in ov->packet_size,
- * though. */
-static int
-ov518_set_packet_size(struct usb_ov511 *ov, int size)
-{
-       int alt;
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       if (ov->bclass == BCL_OV518) {
-               if (size == 0)
-                       alt = OV518_ALT_SIZE_0;
-               else if (size == 128)
-                       alt = OV518_ALT_SIZE_128;
-               else if (size == 256)
-                       alt = OV518_ALT_SIZE_256;
-               else if (size == 384)
-                       alt = OV518_ALT_SIZE_384;
-               else if (size == 512)
-                       alt = OV518_ALT_SIZE_512;
-               else if (size == 640)
-                       alt = OV518_ALT_SIZE_640;
-               else if (size == 768)
-                       alt = OV518_ALT_SIZE_768;
-               else if (size == 896)
-                       alt = OV518_ALT_SIZE_896;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else {
-               err("Set packet size: Invalid bridge type");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d, alt=%d", size, alt);
-
-       ov->packet_size = size;
-       if (size > 0) {
-               /* Program ISO FIFO size reg (packet number isn't included) */
-               ov518_reg_w32(ov, 0x30, size, 2);
-
-               if (ov->packet_numbering)
-                       ++ov->packet_size;
-       }
-
-       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-               err("Set packet size: set interface error");
-               return -EBUSY;
-       }
-
-       /* Initialize the stream */
-       if (reg_w(ov, 0x2f, 0x80) < 0)
-               return -EIO;
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov511_init_compression(struct usb_ov511 *ov)
-{
-       int rc = 0;
-
-       if (!ov->compress_inited) {
-               reg_w(ov, 0x70, phy);
-               reg_w(ov, 0x71, phuv);
-               reg_w(ov, 0x72, pvy);
-               reg_w(ov, 0x73, pvuv);
-               reg_w(ov, 0x74, qhy);
-               reg_w(ov, 0x75, qhuv);
-               reg_w(ov, 0x76, qvy);
-               reg_w(ov, 0x77, qvuv);
-
-               if (ov511_upload_quan_tables(ov) < 0) {
-                       err("Error uploading quantization tables");
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-
-       ov->compress_inited = 1;
-out:
-       return rc;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov518_init_compression(struct usb_ov511 *ov)
-{
-       int rc = 0;
-
-       if (!ov->compress_inited) {
-               if (ov518_upload_quan_tables(ov) < 0) {
-                       err("Error uploading quantization tables");
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-
-       ov->compress_inited = 1;
-out:
-       return rc;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's contrast setting to "val" */
-static int
-sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       {
-               rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_OV6630:
-       {
-               rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_OV7620:
-       {
-               unsigned char ctab[] = {
-                       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
-                       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-               };
-
-               /* Use Y gamma control instead. Bit 0 enables it. */
-               rc = i2c_w(ov, 0x64, ctab[val>>12]);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_SAA7111A:
-       {
-               rc = i2c_w(ov, 0x0b, val >> 9);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       default:
-       {
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-       }
-
-       rc = 0;         /* Success */
-       ov->contrast = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's contrast setting */
-static int
-sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-               rc = i2c_r(ov, OV7610_REG_CNT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_CNT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 12;
-               break;
-       case SEN_OV7620:
-               /* Use Y gamma reg instead. Bit 0 is the enable bit. */
-               rc = i2c_r(ov, 0x64);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = (rc & 0xfe) << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->contrast;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->contrast = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's brightness setting to "val" */
-static int
-sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(4, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-               /* 7620 doesn't like manual changes when in auto mode */
-               if (!ov->auto_brt) {
-                       rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-                       if (rc < 0)
-                               goto out;
-               }
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0a, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->brightness = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's brightness setting */
-static int
-sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV7620:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_BRT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->brightness;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->brightness = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's saturation (color intensity) setting to "val" */
-static int
-sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-//             /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-//             rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
-//             if (rc < 0)
-//                     goto out;
-               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0c, val >> 9);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->colour = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's saturation (color intensity) setting */
-static int
-sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_SAT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV7620:
-//             /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-//             rc = i2c_r(ov, 0x62);
-//             if (rc < 0)
-//                     return rc;
-//             else
-//                     *val = (rc & 0x7e) << 9;
-               rc = i2c_r(ov, OV7610_REG_SAT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->colour;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->colour = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's hue (red/blue balance) setting to "val" */
-static int
-sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
-               if (rc < 0)
-                       goto out;
-
-               rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-// Hue control is causing problems. I will enable it once it's fixed.
-#if 0
-               rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
-               if (rc < 0)
-                       goto out;
-
-               rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
-               if (rc < 0)
-                       goto out;
-#endif
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->hue = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's hue (red/blue balance) setting */
-static int
-sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_BLUE);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV7620:
-               rc = i2c_r(ov, 0x7a);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->hue;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->hue = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static int
-sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-       int rc;
-
-       PDEBUG(4, "sensor_set_picture");
-
-       ov->whiteness = p->whiteness;
-
-       /* Don't return error if a setting is unsupported, or rest of settings
-         * will not be performed */
-
-       rc = sensor_set_contrast(ov, p->contrast);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_brightness(ov, p->brightness);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_saturation(ov, p->colour);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_hue(ov, p->hue);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       return 0;
-}
-
-static int
-sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-       int rc;
-
-       PDEBUG(4, "sensor_get_picture");
-
-       /* Don't return error if a setting is unsupported, or rest of settings
-         * will not be performed */
-
-       rc = sensor_get_contrast(ov, &(p->contrast));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_brightness(ov, &(p->brightness));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_saturation(ov, &(p->colour));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_hue(ov, &(p->hue));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       p->whiteness = 105 << 8;
-
-       return 0;
-}
-
-#if 0
-// FIXME: Exposure range is only 0x00-0x7f in interlace mode
-/* Sets current exposure for sensor. This only has an effect if auto-exposure
- * is off */
-static inline int
-sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               rc = i2c_w(ov, 0x10, val);
-               if (rc < 0)
-                       goto out;
-
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_exposure");
-               return -EINVAL;
-       }
-
-       rc = 0;         /* Success */
-       ov->exposure = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-#endif
-
-/* Gets current exposure level from sensor, regardless of whether it is under
- * manual control. */
-static int
-sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               rc = i2c_r(ov, 0x10);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc;
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               val = NULL;
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for get_exposure");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->exposure = *val;
-
-       return 0;
-}
-
-/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static void
-ov51x_led_control(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->bridge == BRG_OV511PLUS)
-               reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
-       else if (ov->bclass == BCL_OV518)
-               reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
-
-       return;
-}
-
-/* Matches the sensor's internal frame rate to the lighting frequency.
- * Valid frequencies are:
- *     50 - 50Hz, for European and Asian lighting
- *     60 - 60Hz, for American lighting
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_light_freq(struct usb_ov511 *ov, int freq)
-{
-       int sixty;
-
-       PDEBUG(4, "%d Hz", freq);
-
-       if (freq == 60)
-               sixty = 1;
-       else if (freq == 50)
-               sixty = 0;
-       else {
-               err("Invalid light freq (%d Hz)", freq);
-               return -EINVAL;
-       }
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-               i2c_w(ov, 0x2b, sixty?0x00:0xac);
-               i2c_w_mask(ov, 0x13, 0x10, 0x10);
-               i2c_w_mask(ov, 0x13, 0x00, 0x10);
-               break;
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-               i2c_w(ov, 0x2b, sixty?0x00:0xac);
-               i2c_w_mask(ov, 0x76, 0x01, 0x01);
-               break;
-       case SEN_OV6620:
-       case SEN_OV6630:
-               i2c_w(ov, 0x2b, sixty?0xa8:0x28);
-               i2c_w(ov, 0x2a, sixty?0x84:0xa4);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_light_freq");
-               return -EINVAL;
-       }
-
-       ov->lightfreq = freq;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's banding filter, otherwise turn it
- * off. This filter tries to reduce the pattern of horizontal light/dark bands
- * caused by some (usually fluorescent) lighting. The light frequency must be
- * set either before or after enabling it with ov51x_set_light_freq().
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620.
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
-{
-       int rc;
-
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-               || ov->sensor == SEN_SAA7111A) {
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
-       if (rc < 0)
-               return rc;
-
-       ov->bandfilt = enable;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's auto brightness control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
-{
-       int rc;
-
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-               || ov->sensor == SEN_SAA7111A) {
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
-       if (rc < 0)
-               return rc;
-
-       ov->auto_brt = enable;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's auto exposure control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
-               break;
-       case SEN_OV6620:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
-               break;
-       case SEN_OV6630:
-               i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_auto_exposure");
-               return -EINVAL;
-       }
-
-       ov->auto_exp = enable;
-
-       return 0;
-}
-
-/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
- * that are illuminated from behind.
- *
- * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_backlight(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV7620:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-               break;
-       case SEN_OV6620:
-               i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
-               break;
-       case SEN_OV6630:
-               i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-               break;
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_backlight");
-               return -EINVAL;
-       }
-
-       ov->backlight = enable;
-
-       return 0;
-}
-
-static int
-sensor_set_mirror(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_mirror");
-               return -EINVAL;
-       }
-
-       ov->mirror = enable;
-
-       return 0;
-}
-
-/* Returns number of bits per pixel (regardless of where they are located;
- * planar or not), or zero for unsupported format.
- */
-static inline int
-get_depth(int palette)
-{
-       switch (palette) {
-       case VIDEO_PALETTE_GREY:    return 8;
-       case VIDEO_PALETTE_YUV420:  return 12;
-       case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
-       default:                    return 0;  /* Invalid format */
-       }
-}
-
-/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
-get_frame_length(struct ov511_frame *frame)
-{
-       if (!frame)
-               return 0;
-       else
-               return ((frame->width * frame->height
-                        * get_depth(frame->format)) >> 3);
-}
-
-static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
-                        int mode, int sub_flag, int qvga)
-{
-       int clock;
-
-       /******** Mode (VGA/QVGA) and sensor specific regs ********/
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w(ov, 0x14, qvga?0x24:0x04);
-// FIXME: Does this improve the image quality or frame rate?
-#if 0
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, 0x10);
-               i2c_w(ov, 0x25, qvga?0x40:0x8a);
-               i2c_w(ov, 0x2f, qvga?0x30:0xb0);
-               i2c_w(ov, 0x35, qvga?0x1c:0x9c);
-#endif
-               break;
-       case SEN_OV7620:
-//             i2c_w(ov, 0x2b, 0x00);
-               i2c_w(ov, 0x14, qvga?0xa4:0x84);
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, qvga?0x20:0x3a);
-               i2c_w(ov, 0x25, qvga?0x30:0x60);
-               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-               i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
-               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-               break;
-       case SEN_OV76BE:
-//             i2c_w(ov, 0x2b, 0x00);
-               i2c_w(ov, 0x14, qvga?0xa4:0x84);
-// FIXME: Enable this once 7620AE uses 7620 initial settings
-#if 0
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, qvga?0x20:0x3a);
-               i2c_w(ov, 0x25, qvga?0x30:0x60);
-               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-               i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
-               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-#endif
-               break;
-       case SEN_OV6620:
-               i2c_w(ov, 0x14, qvga?0x24:0x04);
-               break;
-       case SEN_OV6630:
-               i2c_w(ov, 0x14, qvga?0xa0:0x80);
-               break;
-       default:
-               err("Invalid sensor");
-               return -EINVAL;
-       }
-
-       /******** Palette-specific regs ********/
-
-       if (mode == VIDEO_PALETTE_GREY) {
-               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-                       /* these aren't valid on the OV6620/OV7620/6630? */
-                       i2c_w_mask(ov, 0x0e, 0x40, 0x40);
-               }
-
-               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-                   && ov518_color) {
-                       i2c_w_mask(ov, 0x12, 0x00, 0x10);
-                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
-               } else {
-                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
-               }
-       } else {
-               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-                       /* not valid on the OV6620/OV7620/6630? */
-                       i2c_w_mask(ov, 0x0e, 0x00, 0x40);
-               }
-
-               /* The OV518 needs special treatment. Although both the OV518
-                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-                * bus is actually used. The UV bus is tied to ground.
-                * Therefore, the OV6630 needs to be in 8-bit multiplexed
-                * output mode */
-
-               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-                   && ov518_color) {
-                       i2c_w_mask(ov, 0x12, 0x10, 0x10);
-                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
-               } else {
-                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
-               }
-       }
-
-       /******** Clock programming ********/
-
-       /* The OV6620 needs special handling. This prevents the 
-        * severe banding that normally occurs */
-       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
-       {
-               /* Clock down */
-
-               i2c_w(ov, 0x2a, 0x04);
-
-               if (ov->compress) {
-//                     clock = 0;    /* This ensures the highest frame rate */
-                       clock = 3;
-               } else if (clockdiv == -1) {   /* If user didn't override it */
-                       clock = 3;    /* Gives better exposure time */
-               } else {
-                       clock = clockdiv;
-               }
-
-               PDEBUG(4, "Setting clock divisor to %d", clock);
-
-               i2c_w(ov, 0x11, clock);
-
-               i2c_w(ov, 0x2a, 0x84);
-               /* This next setting is critical. It seems to improve
-                * the gain or the contrast. The "reserved" bits seem
-                * to have some effect in this case. */
-               i2c_w(ov, 0x2d, 0x85);
-       }
-       else
-       {
-               if (ov->compress) {
-                       clock = 1;    /* This ensures the highest frame rate */
-               } else if (clockdiv == -1) {   /* If user didn't override it */
-                       /* Calculate and set the clock divisor */
-                       clock = ((sub_flag ? ov->subw * ov->subh
-                                 : width * height)
-                                * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
-                                / 66000;
-               } else {
-                       clock = clockdiv;
-               }
-
-               PDEBUG(4, "Setting clock divisor to %d", clock);
-
-               i2c_w(ov, 0x11, clock);
-       }
-
-       /******** Special Features ********/
-
-       if (framedrop >= 0)
-               i2c_w(ov, 0x16, framedrop);
-
-       /* Test Pattern */
-       i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
-
-       /* Enable auto white balance */
-       i2c_w_mask(ov, 0x12, 0x04, 0x04);
-
-       // This will go away as soon as ov51x_mode_init_sensor_regs()
-       // is fully tested.
-       /* 7620/6620/6630? don't have register 0x35, so play it safe */
-       if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-               if (width == 640 && height == 480)
-                       i2c_w(ov, 0x35, 0x9e);
-               else
-                       i2c_w(ov, 0x35, 0x1e);
-       }
-
-       return 0;
-}
-
-static int
-set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
-                    int sub_flag)
-{
-       int ret;
-       int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; 
-       int hoffset, voffset, hwscale = 0, vwscale = 0;
-
-       /* The different sensor ICs handle setting up of window differently.
-        * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-               hwsbase = 0x38;
-               hwebase = 0x3a;
-               vwsbase = vwebase = 0x05;
-               break;
-       case SEN_OV6620:
-       case SEN_OV6630:
-               hwsbase = 0x38;
-               hwebase = 0x3a;
-               vwsbase = 0x05;
-               vwebase = 0x06;
-               break;
-       case SEN_OV7620:
-               hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
-               hwebase = 0x2f;
-               vwsbase = vwebase = 0x05;
-               break;
-       default:
-               err("Invalid sensor");
-               return -EINVAL;
-       }
-
-       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
-               /* Note: OV518(+) does downsample on its own) */
-               if ((width > 176 && height > 144)
-                   || ov->bclass == BCL_OV518) {  /* CIF */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 0);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 1;
-                       vwscale = 1;  /* The datasheet says 0; it's wrong */
-                       hwsize = 352;
-                       vwsize = 288;
-               } else if (width > 176 || height > 144) {
-                       err("Illegal dimensions");
-                       return -EINVAL;
-               } else {                            /* QCIF */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 1);
-                       if (ret < 0)
-                               return ret;
-                       hwsize = 176;
-                       vwsize = 144;
-               }
-       } else {
-               if (width > 320 && height > 240) {  /* VGA */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 0);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 2;
-                       vwscale = 1;
-                       hwsize = 640;
-                       vwsize = 480;
-               } else if (width > 320 || height > 240) {
-                       err("Illegal dimensions");
-                       return -EINVAL;
-               } else {                            /* QVGA */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 1);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 1;
-                       hwsize = 320;
-                       vwsize = 240;
-               }
-       }
-
-       /* Center the window */
-       hoffset = ((hwsize - width) / 2) >> hwscale;
-       voffset = ((vwsize - height) / 2) >> vwscale;
-
-       /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
-       if (sub_flag) {
-               i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
-               i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
-               i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
-               i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
-       } else {
-               i2c_w(ov, 0x17, hwsbase + hoffset);
-               i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
-               i2c_w(ov, 0x19, vwsbase + voffset);
-               i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
-       }
-
-#ifdef OV511_DEBUG
-       if (dump_sensor)
-               dump_i2c_regs(ov);
-#endif
-
-       return 0;
-}
-
-/* Set up the OV511/OV511+ with the given image parameters.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov511_mode_init_regs(struct usb_ov511 *ov,
-                    int width, int height, int mode, int sub_flag)
-{
-       int hsegs, vsegs;
-
-       if (sub_flag) {
-               width = ov->subw;
-               height = ov->subh;
-       }
-
-       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-              width, height, mode, sub_flag);
-
-       // FIXME: This should be moved to a 7111a-specific function once
-       // subcapture is dealt with properly
-       if (ov->sensor == SEN_SAA7111A) {
-               if (width == 320 && height == 240) {
-                       /* No need to do anything special */
-               } else if (width == 640 && height == 480) {
-                       /* Set the OV511 up as 320x480, but keep the
-                        * V4L resolution as 640x480 */
-                       width = 320;
-               } else {
-                       err("SAA7111A only allows 320x240 or 640x480");
-                       return -EINVAL;
-               }
-       }
-
-       /* Make sure width and height are a multiple of 8 */
-       if (width % 8 || height % 8) {
-               err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
-               return -EINVAL;
-       }
-
-       if (width < ov->minwidth || height < ov->minheight) {
-               err("Requested dimensions are too small");
-               return -EINVAL;
-       }
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       if (mode == VIDEO_PALETTE_GREY) {
-               reg_w(ov, R511_CAM_UV_EN, 0x00);
-               reg_w(ov, R511_SNAP_UV_EN, 0x00);
-               reg_w(ov, R511_SNAP_OPTS, 0x01);
-       } else {
-               reg_w(ov, R511_CAM_UV_EN, 0x01);
-               reg_w(ov, R511_SNAP_UV_EN, 0x01);
-               reg_w(ov, R511_SNAP_OPTS, 0x03);
-       }
-
-       /* Here I'm assuming that snapshot size == image size.
-        * I hope that's always true. --claudio
-        */
-       hsegs = (width >> 3) - 1;
-       vsegs = (height >> 3) - 1;
-
-       reg_w(ov, R511_CAM_PXCNT, hsegs);
-       reg_w(ov, R511_CAM_LNCNT, vsegs);
-       reg_w(ov, R511_CAM_PXDIV, 0x00);
-       reg_w(ov, R511_CAM_LNDIV, 0x00);
-
-       /* YUV420, low pass filter on */
-       reg_w(ov, R511_CAM_OPTS, 0x03);
-
-       /* Snapshot additions */
-       reg_w(ov, R511_SNAP_PXCNT, hsegs);
-       reg_w(ov, R511_SNAP_LNCNT, vsegs);
-       reg_w(ov, R511_SNAP_PXDIV, 0x00);
-       reg_w(ov, R511_SNAP_LNDIV, 0x00);
-
-       if (ov->compress) {
-               /* Enable Y and UV quantization and compression */
-               reg_w(ov, R511_COMP_EN, 0x07);
-               reg_w(ov, R511_COMP_LUT_EN, 0x03);
-               ov51x_reset(ov, OV511_RESET_OMNICE);
-       }
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Sets up the OV518/OV518+ with the given image parameters
- *
- * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Also, only 15 FPS is supported now.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov518_mode_init_regs(struct usb_ov511 *ov,
-                    int width, int height, int mode, int sub_flag)
-{
-       int hsegs, vsegs, hi_res;
-
-       if (sub_flag) {
-               width = ov->subw;
-               height = ov->subh;
-       }
-
-       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-              width, height, mode, sub_flag);
-
-       if (width % 16 || height % 8) {
-               err("Invalid size (%d, %d)", width, height);
-               return -EINVAL;
-       }
-
-       if (width < ov->minwidth || height < ov->minheight) {
-               err("Requested dimensions are too small");
-               return -EINVAL;
-       }
-
-       if (width >= 320 && height >= 240) {
-               hi_res = 1;
-       } else if (width >= 320 || height >= 240) {
-               err("Invalid width/height combination (%d, %d)", width, height);
-               return -EINVAL;
-       } else {
-               hi_res = 0;
-       }
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       /******** Set the mode ********/
-
-       reg_w(ov, 0x2b, 0);
-       reg_w(ov, 0x2c, 0);
-       reg_w(ov, 0x2d, 0);
-       reg_w(ov, 0x2e, 0);
-       reg_w(ov, 0x3b, 0);
-       reg_w(ov, 0x3c, 0);
-       reg_w(ov, 0x3d, 0);
-       reg_w(ov, 0x3e, 0);
-
-       if (ov->bridge == BRG_OV518 && ov518_color) {
-               /* OV518 needs U and V swapped */
-               i2c_w_mask(ov, 0x15, 0x00, 0x01);
-
-               if (mode == VIDEO_PALETTE_GREY) {
-                       /* Set 16-bit input format (UV data are ignored) */
-                       reg_w_mask(ov, 0x20, 0x00, 0x08);
-
-                       /* Set 8-bit (4:0:0) output format */
-                       reg_w_mask(ov, 0x28, 0x00, 0xf0);
-                       reg_w_mask(ov, 0x38, 0x00, 0xf0);
-               } else {
-                       /* Set 8-bit (YVYU) input format */
-                       reg_w_mask(ov, 0x20, 0x08, 0x08);
-
-                       /* Set 12-bit (4:2:0) output format */
-                       reg_w_mask(ov, 0x28, 0x80, 0xf0);
-                       reg_w_mask(ov, 0x38, 0x80, 0xf0);
-               }
-       } else {
-               reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-               reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-       }
-
-       hsegs = width / 16;
-       vsegs = height / 4;
-
-       reg_w(ov, 0x29, hsegs);
-       reg_w(ov, 0x2a, vsegs);
-
-       reg_w(ov, 0x39, hsegs);
-       reg_w(ov, 0x3a, vsegs);
-
-       /* Windows driver does this here; who knows why */
-       reg_w(ov, 0x2f, 0x80);
-
-       /******** Set the framerate (to 15 FPS) ********/
-
-       /* Mode independent, but framerate dependent, regs */
-       reg_w(ov, 0x51, 0x02);  /* Clock divider; lower==faster */
-       reg_w(ov, 0x22, 0x18);
-       reg_w(ov, 0x23, 0xff);
-
-       if (ov->bridge == BRG_OV518PLUS)
-               reg_w(ov, 0x21, 0x19);
-       else
-               reg_w(ov, 0x71, 0x19);  /* Compression-related? */
-
-       // FIXME: Sensor-specific
-       /* Bit 5 is what matters here. Of course, it is "reserved" */
-       i2c_w(ov, 0x54, 0x23);
-
-       reg_w(ov, 0x2f, 0x80);
-
-       if (ov->bridge == BRG_OV518PLUS) {
-               reg_w(ov, 0x24, 0x94);
-               reg_w(ov, 0x25, 0x90);
-               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
-               ov518_reg_w32(ov, 0xc6,    540, 2);     /* 21ch   */
-               ov518_reg_w32(ov, 0xc7,    540, 2);     /* 21ch   */
-               ov518_reg_w32(ov, 0xc8,    108, 2);     /* 6ch    */
-               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
-               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
-               ov518_reg_w32(ov, 0xcc,   2400, 2);     /* 960h   */
-               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
-               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
-       } else {
-               reg_w(ov, 0x24, 0x9f);
-               reg_w(ov, 0x25, 0x90);
-               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
-               ov518_reg_w32(ov, 0xc6,    500, 2);     /* 1f4h   */
-               ov518_reg_w32(ov, 0xc7,    500, 2);     /* 1f4h   */
-               ov518_reg_w32(ov, 0xc8,    142, 2);     /* 8eh    */
-               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
-               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
-               ov518_reg_w32(ov, 0xcc,   2000, 2);     /* 7d0h   */
-               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
-               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
-       }
-
-       reg_w(ov, 0x2f, 0x80);
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       /* Reset it just for good measure */
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* This is a wrapper around the OV511, OV518, and sensor specific functions */
-static int
-mode_init_regs(struct usb_ov511 *ov,
-              int width, int height, int mode, int sub_flag)
-{
-       int rc = 0;
-
-       if (!ov || !ov->dev)
-               return -EFAULT;
-
-       if (ov->bclass == BCL_OV518) {
-               rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
-       } else {
-               rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
-       }
-
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-               err("KS0127-series decoders not supported yet");
-               rc = -EINVAL;
-               break;
-       case SEN_SAA7111A:
-//             rc = mode_init_saa_sensor_regs(ov, width, height, mode,
-//                                            sub_flag);
-
-               PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
-               break;
-       default:
-               err("Unknown sensor");
-               rc = -EINVAL;
-       }
-
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       /* Sensor-independent settings */
-       rc = sensor_set_auto_brightness(ov, ov->auto_brt);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_auto_exposure(ov, ov->auto_exp);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_banding_filter(ov, bandingfilter);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       if (ov->lightfreq) {
-               rc = sensor_set_light_freq(ov, lightfreq);
-               if (FATAL_ERROR(rc))
-                       return rc;
-       }
-
-       rc = sensor_set_backlight(ov, ov->backlight);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_mirror(ov, ov->mirror);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       return 0;
-}
-
-/* This sets the default image parameters. This is useful for apps that use
- * read() and do not set these.
- */
-static int
-ov51x_set_default_params(struct usb_ov511 *ov)
-{
-       int i;
-
-       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
-        * (using read() instead). */
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].width = ov->maxwidth;
-               ov->frame[i].height = ov->maxheight;
-               ov->frame[i].bytes_read = 0;
-               if (force_palette)
-                       ov->frame[i].format = force_palette;
-               else
-                       ov->frame[i].format = VIDEO_PALETTE_YUV420;
-
-               ov->frame[i].depth = get_depth(ov->frame[i].format);
-       }
-
-       PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
-              symbolic(v4l1_plist, ov->frame[0].format));
-
-       /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
-       if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
-                          ov->frame[0].format, 0) < 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-/**********************************************************************
- *
- * Video decoder stuff
- *
- **********************************************************************/
-
-/* Set analog input port of decoder */
-static int
-decoder_set_input(struct usb_ov511 *ov, int input)
-{
-       PDEBUG(4, "port %d", input);
-
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               /* Select mode */
-               i2c_w_mask(ov, 0x02, input, 0x07);
-               /* Bypass chrominance trap for modes 4..7 */
-               i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Get ASCII name of video input */
-static int
-decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
-{
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               if (input < 0 || input > 7)
-                       return -EINVAL;
-               else if (input < 4)
-                       sprintf(name, "CVBS-%d", input);
-               else // if (input < 8)
-                       sprintf(name, "S-Video-%d", input - 4);
-               break;
-       }
-       default:
-               sprintf(name, "%s", "Camera");
-       }
-
-       return 0;
-}
-
-/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
-decoder_set_norm(struct usb_ov511 *ov, int norm)
-{
-       PDEBUG(4, "%d", norm);
-
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               int reg_8, reg_e;
-
-               if (norm == VIDEO_MODE_NTSC) {
-                       reg_8 = 0x40;   /* 60 Hz */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_PAL) {
-                       reg_8 = 0x00;   /* 50 Hz */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_AUTO) {
-                       reg_8 = 0x80;   /* Auto field detect */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_SECAM) {
-                       reg_8 = 0x00;   /* 50 Hz */
-                       reg_e = 0x50;   /* SECAM / PAL 4.43 */
-               } else {
-                       return -EINVAL;
-               }
-
-               i2c_w_mask(ov, 0x08, reg_8, 0xc0);
-               i2c_w_mask(ov, 0x0e, reg_e, 0x70);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**********************************************************************
- *
- * Raw data parsing
- *
- **********************************************************************/
-
-/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * image at pOut is specified by w.
- */
-static inline void
-make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
-{
-       unsigned char *pOut1 = pOut;
-       int x, y;
-
-       for (y = 0; y < 8; y++) {
-               pOut1 = pOut;
-               for (x = 0; x < 8; x++) {
-                       *pOut1++ = *pIn++;
-               }
-               pOut += w;
-       }
-}
-
-/*
- * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
- * The segments represent 4 squares of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127        248 249 ... 255
- *
- */ 
-static void
-yuv400raw_to_yuv400p(struct ov511_frame *frame,
-                    unsigned char *pIn0, unsigned char *pOut0)
-{
-       int x, y;
-       unsigned char *pIn, *pOut, *pOutLine;
-
-       /* Copy Y */
-       pIn = pIn0;
-       pOutLine = pOut0;
-       for (y = 0; y < frame->rawheight - 1; y += 8) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 8) {
-                       make_8x8(pIn, pOut, frame->rawwidth);
-                       pIn += 64;
-                       pOut += 8;
-               }
-               pOutLine += 8 * frame->rawwidth;
-       }
-}
-
-/*
- * For YUV 4:2:0 images, the data show up in 384 byte segments.
- * The first 64 bytes of each segment are U, the next 64 are V.  The U and
- * V are arranged as follows:
- *
- *      0  1 ...  7
- *      8  9 ... 15
- *           ...   
- *     56 57 ... 63
- *
- * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
- *
- * The next 256 bytes are full resolution Y data and represent 4 squares
- * of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
- *
- * Note that the U and V data in one segment represent a 16 x 16 pixel
- * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
- * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
- * next horizontal stripe.
- *
- * If dumppix module param is set, _parse_data just dumps the incoming segments,
- * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
- * this puts the data on the standard output and can be analyzed with the
- * parseppm.c utility I wrote.  That's a much faster way for figuring out how
- * these data are scrambled.
- */
-
-/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
- *
- * FIXME: Currently only handles width and height that are multiples of 16
- */
-static void
-yuv420raw_to_yuv420p(struct ov511_frame *frame,
-                    unsigned char *pIn0, unsigned char *pOut0)
-{
-       int k, x, y;
-       unsigned char *pIn, *pOut, *pOutLine;
-       const unsigned int a = frame->rawwidth * frame->rawheight;
-       const unsigned int w = frame->rawwidth / 2;
-
-       /* Copy U and V */
-       pIn = pIn0;
-       pOutLine = pOut0 + a;
-       for (y = 0; y < frame->rawheight - 1; y += 16) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 16) {
-                       make_8x8(pIn, pOut, w);
-                       make_8x8(pIn + 64, pOut + a/4, w);
-                       pIn += 384;
-                       pOut += 8;
-               }
-               pOutLine += 8 * w;
-       }
-
-       /* Copy Y */
-       pIn = pIn0 + 128;
-       pOutLine = pOut0;
-       k = 0;
-       for (y = 0; y < frame->rawheight - 1; y += 8) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 8) {
-                       make_8x8(pIn, pOut, frame->rawwidth);
-                       pIn += 64;
-                       pOut += 8;
-                       if ((++k) > 3) {
-                               k = 0;
-                               pIn += 128;
-                       }
-               }
-               pOutLine += 8 * frame->rawwidth;
-       }
-}
-
-/**********************************************************************
- *
- * Decompression
- *
- **********************************************************************/
-
-static int
-request_decompressor(struct usb_ov511 *ov)
-{
-       if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
-               err("No decompressor available");
-       } else {
-               err("Unknown bridge");
-       }
-
-       return -ENOSYS;
-}
-
-static void
-decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
-          unsigned char *pIn0, unsigned char *pOut0)
-{
-       if (!ov->decomp_ops)
-               if (request_decompressor(ov))
-                       return;
-
-}
-
-/**********************************************************************
- *
- * Format conversion
- *
- **********************************************************************/
-
-/* Fuses even and odd fields together, and doubles width.
- * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
- * OUTPUT: a normal YUV planar image, with correct aspect ratio
- */
-static void
-deinterlace(struct ov511_frame *frame, int rawformat,
-            unsigned char *pIn0, unsigned char *pOut0)
-{
-       const int fieldheight = frame->rawheight / 2;
-       const int fieldpix = fieldheight * frame->rawwidth;
-       const int w = frame->width;
-       int x, y;
-       unsigned char *pInEven, *pInOdd, *pOut;
-
-       PDEBUG(5, "fieldheight=%d", fieldheight);
-
-       if (frame->rawheight != frame->height) {
-               err("invalid height");
-               return;
-       }
-
-       if ((frame->rawwidth * 2) != frame->width) {
-               err("invalid width");
-               return;
-       }
-
-       /* Y */
-       pInOdd = pIn0;
-       pInEven = pInOdd + fieldpix;
-       pOut = pOut0;
-       for (y = 0; y < fieldheight; y++) {
-               for (x = 0; x < frame->rawwidth; x++) {
-                       *pOut = *pInEven;
-                       *(pOut+1) = *pInEven++;
-                       *(pOut+w) = *pInOdd;
-                       *(pOut+w+1) = *pInOdd++;
-                       pOut += 2;
-               }
-               pOut += w;
-       }
-
-       if (rawformat == RAWFMT_YUV420) {
-       /* U */
-               pInOdd = pIn0 + fieldpix * 2;
-               pInEven = pInOdd + fieldpix / 4;
-               for (y = 0; y < fieldheight / 2; y++) {
-                       for (x = 0; x < frame->rawwidth / 2; x++) {
-                               *pOut = *pInEven;
-                               *(pOut+1) = *pInEven++;
-                               *(pOut+w/2) = *pInOdd;
-                               *(pOut+w/2+1) = *pInOdd++;
-                               pOut += 2;
-                       }
-                       pOut += w/2;
-               }
-       /* V */
-               pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
-               pInEven = pInOdd + fieldpix / 4;
-               for (y = 0; y < fieldheight / 2; y++) {
-                       for (x = 0; x < frame->rawwidth / 2; x++) {
-                               *pOut = *pInEven;
-                               *(pOut+1) = *pInEven++;
-                               *(pOut+w/2) = *pInOdd;
-                               *(pOut+w/2+1) = *pInOdd++;
-                               pOut += 2;
-                       }
-                       pOut += w/2;
-               }
-       }
-}
-
-static void
-ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-               /* Deinterlace frame, if necessary */
-               if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-                       if (frame->compressed)
-                               decompress(ov, frame, frame->rawdata,
-                                                frame->tempdata);
-                       else
-                               yuv400raw_to_yuv400p(frame, frame->rawdata,
-                                                    frame->tempdata);
-
-                       deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
-                                   frame->data);
-               } else {
-                       if (frame->compressed)
-                               decompress(ov, frame, frame->rawdata,
-                                                frame->data);
-                       else
-                               yuv400raw_to_yuv400p(frame, frame->rawdata,
-                                                    frame->data);
-               }
-}
-
-/* Process raw YUV420 data into standard YUV420P */
-static void
-ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-       /* Deinterlace frame, if necessary */
-       if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-               if (frame->compressed)
-                       decompress(ov, frame, frame->rawdata, frame->tempdata);
-               else
-                       yuv420raw_to_yuv420p(frame, frame->rawdata,
-                                            frame->tempdata);
-
-               deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
-                           frame->data);
-       } else {
-               if (frame->compressed)
-                       decompress(ov, frame, frame->rawdata, frame->data);
-               else
-                       yuv420raw_to_yuv420p(frame, frame->rawdata,
-                                            frame->data);
-       }
-}
-
-/* Post-processes the specified frame. This consists of:
- *     1. Decompress frame, if necessary
- *     2. Deinterlace frame and scale to proper size, if necessary
- *     3. Convert from YUV planar to destination format, if necessary
- *     4. Fix the RGB offset, if necessary
- */
-static void
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-       if (dumppix) {
-               memset(frame->data, 0,
-                       MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-               PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-               memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
-       } else {
-               switch (frame->format) {
-               case VIDEO_PALETTE_GREY:
-                       ov51x_postprocess_grey(ov, frame);
-                       break;
-               case VIDEO_PALETTE_YUV420:
-               case VIDEO_PALETTE_YUV420P:
-                       ov51x_postprocess_yuv420(ov, frame);
-                       break;
-               default:
-                       err("Cannot convert data to %s",
-                           symbolic(v4l1_plist, frame->format));
-               }
-       }
-}
-
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static inline void
-ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-       int num, offset;
-       int pnum = in[ov->packet_size - 1];             /* Get packet number */
-       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-       struct ov511_frame *frame = &ov->frame[ov->curframe];
-       struct timeval *ts;
-
-       /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-        * byte non-zero. The EOF packet has image width/height in the
-        * 10th and 11th bytes. The 9th byte is given as follows:
-        *
-        * bit 7: EOF
-        *     6: compression enabled
-        *     5: 422/420/400 modes
-        *     4: 422/420/400 modes
-        *     3: 1
-        *     2: snapshot button on
-        *     1: snapshot frame
-        *     0: even/odd field
-        */
-
-       if (printph) {
-               info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-                    pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
-                    in[7], in[8], in[9], in[10], in[11]);
-       }
-
-       /* Check for SOF/EOF packet */
-       if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
-           (~in[8] & 0x08))
-               goto check_middle;
-
-       /* Frame end */
-       if (in[8] & 0x80) {
-               ts = (struct timeval *)(frame->data
-                     + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-               do_gettimeofday(ts);
-
-               /* Get the actual frame size from the EOF header */
-               frame->rawwidth = ((int)(in[9]) + 1) * 8;
-               frame->rawheight = ((int)(in[10]) + 1) * 8;
-
-               PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
-                       ov->curframe, pnum, frame->rawwidth, frame->rawheight,
-                       frame->bytes_recvd);
-
-               /* Validate the header data */
-               RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-               RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
-                                 ov->maxheight);
-
-               /* Don't allow byte count to exceed buffer size */
-               RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-               if (frame->scanstate == STATE_LINES) {
-                       int nextf;
-
-                       frame->grabstate = FRAME_DONE;
-                       wake_up_interruptible(&frame->wq);
-
-                       /* If next frame is ready or grabbing,
-                        * point to it */
-                       nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-                       if (ov->frame[nextf].grabstate == FRAME_READY
-                           || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-                               ov->curframe = nextf;
-                               ov->frame[nextf].scanstate = STATE_SCANNING;
-                       } else {
-                               if (frame->grabstate == FRAME_DONE) {
-                                       PDEBUG(4, "** Frame done **");
-                               } else {
-                                       PDEBUG(4, "Frame not ready? state = %d",
-                                               ov->frame[nextf].grabstate);
-                               }
-
-                               ov->curframe = -1;
-                       }
-               } else {
-                       PDEBUG(5, "Frame done, but not scanning");
-               }
-               /* Image corruption caused by misplaced frame->segment = 0
-                * fixed by carlosf@conectiva.com.br
-                */
-       } else {
-               /* Frame start */
-               PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
-               /* Check to see if it's a snapshot frame */
-               /* FIXME?? Should the snapshot reset go here? Performance? */
-               if (in[8] & 0x02) {
-                       frame->snapshot = 1;
-                       PDEBUG(3, "snapshot detected");
-               }
-
-               frame->scanstate = STATE_LINES;
-               frame->bytes_recvd = 0;
-               frame->compressed = in[8] & 0x40;
-       }
-
-check_middle:
-       /* Are we in a frame? */
-       if (frame->scanstate != STATE_LINES) {
-               PDEBUG(5, "Not in a frame; packet skipped");
-               return;
-       }
-
-       /* If frame start, skip header */
-       if (frame->bytes_recvd == 0)
-               offset = 9;
-       else
-               offset = 0;
-
-       num = n - offset - 1;
-
-       /* Dump all data exactly as received */
-       if (dumppix == 2) {
-               frame->bytes_recvd += n - 1;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
-                               in, n - 1);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else if (!frame->compressed && !remove_zeros) {
-               frame->bytes_recvd += num;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - num,
-                               in + offset, num);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-               int b, read = 0, allzero, copied = 0;
-               if (offset) {
-                       frame->bytes_recvd += 32 - offset;      // Bytes out
-                       memcpy(frame->rawdata,  in + offset, 32 - offset);
-                       read += 32;
-               }
-
-               while (read < n - 1) {
-                       allzero = 1;
-                       for (b = 0; b < 32; b++) {
-                               if (in[read + b]) {
-                                       allzero = 0;
-                                       break;
-                               }
-                       }
-
-                       if (allzero) {
-                               /* Don't copy it */
-                       } else {
-                               if (frame->bytes_recvd + copied + 32 <= max_raw)
-                               {
-                                       memcpy(frame->rawdata
-                                               + frame->bytes_recvd + copied,
-                                               in + read, 32);
-                                       copied += 32;
-                               } else {
-                                       PDEBUG(3, "Raw data buffer overrun!!");
-                               }
-                       }
-                       read += 32;
-               }
-
-               frame->bytes_recvd += copied;
-       }
-}
-
-static inline void
-ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-       struct ov511_frame *frame = &ov->frame[ov->curframe];
-       struct timeval *ts;
-
-       /* Don't copy the packet number byte */
-       if (ov->packet_numbering)
-               --n;
-
-       /* A false positive here is likely, until OVT gives me
-        * the definitive SOF/EOF format */
-       if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
-               if (printph) {
-                       info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
-                            in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
-               }
-
-               if (frame->scanstate == STATE_LINES) {
-                       PDEBUG(4, "Detected frame end/start");
-                       goto eof;
-               } else { //scanstate == STATE_SCANNING
-                       /* Frame start */
-                       PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-                       goto sof;
-               }
-       } else {
-               goto check_middle;
-       }
-
-eof:
-       ts = (struct timeval *)(frame->data
-             + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-       do_gettimeofday(ts);
-
-       PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-               ov->curframe,
-               (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
-
-       // FIXME: Since we don't know the header formats yet,
-       // there is no way to know what the actual image size is
-       frame->rawwidth = frame->width;
-       frame->rawheight = frame->height;
-
-       /* Validate the header data */
-       RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-       RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-       /* Don't allow byte count to exceed buffer size */
-       RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-       if (frame->scanstate == STATE_LINES) {
-               int nextf;
-
-               frame->grabstate = FRAME_DONE;
-               wake_up_interruptible(&frame->wq);
-
-               /* If next frame is ready or grabbing,
-                * point to it */
-               nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-               if (ov->frame[nextf].grabstate == FRAME_READY
-                   || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-                       ov->curframe = nextf;
-                       ov->frame[nextf].scanstate = STATE_SCANNING;
-                       frame = &ov->frame[nextf];
-               } else {
-                       if (frame->grabstate == FRAME_DONE) {
-                               PDEBUG(4, "** Frame done **");
-                       } else {
-                               PDEBUG(4, "Frame not ready? state = %d",
-                                      ov->frame[nextf].grabstate);
-                       }
-
-                       ov->curframe = -1;
-                       PDEBUG(4, "SOF dropped (no active frame)");
-                       return;  /* Nowhere to store this frame */
-               }
-       }
-sof:
-       PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-
-// Snapshot not reverse-engineered yet.
-#if 0
-       /* Check to see if it's a snapshot frame */
-       /* FIXME?? Should the snapshot reset go here? Performance? */
-       if (in[8] & 0x02) {
-               frame->snapshot = 1;
-               PDEBUG(3, "snapshot detected");
-       }
-#endif
-       frame->scanstate = STATE_LINES;
-       frame->bytes_recvd = 0;
-       frame->compressed = 1;
-
-check_middle:
-       /* Are we in a frame? */
-       if (frame->scanstate != STATE_LINES) {
-               PDEBUG(4, "scanstate: no SOF yet");
-               return;
-       }
-
-       /* Dump all data exactly as received */
-       if (dumppix == 2) {
-               frame->bytes_recvd += n;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else {
-               /* All incoming data are divided into 8-byte segments. If the
-                * segment contains all zero bytes, it must be skipped. These
-                * zero-segments allow the OV518 to mainain a constant data rate
-                * regardless of the effectiveness of the compression. Segments
-                * are aligned relative to the beginning of each isochronous
-                * packet. The first segment in each image is a header (the
-                * decompressor skips it later).
-                */
-
-               int b, read = 0, allzero, copied = 0;
-
-               while (read < n) {
-                       allzero = 1;
-                       for (b = 0; b < 8; b++) {
-                               if (in[read + b]) {
-                                       allzero = 0;
-                                       break;
-                               }
-                       }
-
-                       if (allzero) {
-                       /* Don't copy it */
-                       } else {
-                               if (frame->bytes_recvd + copied + 8 <= max_raw)
-                               {
-                                       memcpy(frame->rawdata
-                                               + frame->bytes_recvd + copied,
-                                               in + read, 8);
-                                       copied += 8;
-                               } else {
-                                       PDEBUG(3, "Raw data buffer overrun!!");
-                               }
-                       }
-                       read += 8;
-               }
-               frame->bytes_recvd += copied;
-       }
-}
-
-static void
-ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs)
-{
-       int i;
-       struct usb_ov511 *ov;
-       struct ov511_sbuf *sbuf;
-
-       if (!urb->context) {
-               PDEBUG(4, "no context");
-               return;
-       }
-
-       sbuf = urb->context;
-       ov = sbuf->ov;
-
-       if (!ov || !ov->dev || !ov->user) {
-               PDEBUG(4, "no device, or not open");
-               return;
-       }
-
-       if (!ov->streaming) {
-               PDEBUG(4, "hmmm... not streaming, but got interrupt");
-               return;
-       }
-
-        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-                PDEBUG(4, "URB unlinked");
-                return;
-        }
-
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
-               err("ERROR: urb->status=%d: %s", urb->status,
-                   symbolic(urb_errlist, urb->status));
-       }
-
-       /* Copy the data received into our frame buffer */
-       PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
-              urb->number_of_packets);
-       for (i = 0; i < urb->number_of_packets; i++) {
-               /* Warning: Don't call *_move_data() if no frame active! */
-               if (ov->curframe >= 0) {
-                       int n = urb->iso_frame_desc[i].actual_length;
-                       int st = urb->iso_frame_desc[i].status;
-                       unsigned char *cdata;
-
-                       urb->iso_frame_desc[i].actual_length = 0;
-                       urb->iso_frame_desc[i].status = 0;
-
-                       cdata = urb->transfer_buffer
-                               + urb->iso_frame_desc[i].offset;
-
-                       if (!n) {
-                               PDEBUG(4, "Zero-length packet");
-                               continue;
-                       }
-
-                       if (st)
-                               PDEBUG(2, "data error: [%d] len=%d, status=%d",
-                                      i, n, st);
-
-                       if (ov->bclass == BCL_OV511)
-                               ov511_move_data(ov, cdata, n);
-                       else if (ov->bclass == BCL_OV518)
-                               ov518_move_data(ov, cdata, n);
-                       else
-                               err("Unknown bridge device (%d)", ov->bridge);
-
-               } else if (waitqueue_active(&ov->wq)) {
-                       wake_up_interruptible(&ov->wq);
-               }
-       }
-
-       /* Resubmit this URB */
-       urb->dev = ov->dev;
-       if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
-               err("usb_submit_urb() ret %d", i);
-
-       return;
-}
-
-/****************************************************************************
- *
- * Stream initialization and termination
- *
- ***************************************************************************/
-
-static int
-ov51x_init_isoc(struct usb_ov511 *ov)
-{
-       struct urb *urb;
-       int fx, err, n, size;
-
-       PDEBUG(3, "*** Initializing capture ***");
-
-       ov->curframe = -1;
-
-       if (ov->bridge == BRG_OV511) {
-               if (cams == 1)
-                       size = 993;
-               else if (cams == 2)
-                       size = 513;
-               else if (cams == 3 || cams == 4)
-                       size = 257;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (cams == 1)
-                       size = 961;
-               else if (cams == 2)
-                       size = 513;
-               else if (cams == 3 || cams == 4)
-                       size = 257;
-               else if (cams >= 5 && cams <= 8)
-                       size = 129;
-               else if (cams >= 9 && cams <= 31)
-                       size = 33;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               if (cams == 1)
-                       size = 896;
-               else if (cams == 2)
-                       size = 512;
-               else if (cams == 3 || cams == 4)
-                       size = 256;
-               else if (cams >= 5 && cams <= 8)
-                       size = 128;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else {
-               err("invalid bridge type");
-               return -1;
-       }
-
-       // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-       if (ov->bclass == BCL_OV518) {
-               if (packetsize == -1) {
-                       ov518_set_packet_size(ov, 640);
-               } else {
-                       info("Forcing packet size to %d", packetsize);
-                       ov518_set_packet_size(ov, packetsize);
-               }
-       } else {
-               if (packetsize == -1) {
-                       ov511_set_packet_size(ov, size);
-               } else {
-                       info("Forcing packet size to %d", packetsize);
-                       ov511_set_packet_size(ov, packetsize);
-               }
-       }
-
-       for (n = 0; n < OV511_NUMSBUF; n++) {
-               urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-               if (!urb) {
-                       err("init isoc: usb_alloc_urb ret. NULL");
-                       return -ENOMEM;
-               }
-               ov->sbuf[n].urb = urb;
-               urb->dev = ov->dev;
-               urb->context = &ov->sbuf[n];
-               urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = ov->sbuf[n].data;
-               urb->complete = ov51x_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
-               urb->interval = 1;
-               for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-                       urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
-                       urb->iso_frame_desc[fx].length = ov->packet_size;
-               }
-       }
-
-       ov->streaming = 1;
-
-       for (n = 0; n < OV511_NUMSBUF; n++) {
-               ov->sbuf[n].urb->dev = ov->dev;
-               err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
-               if (err) {
-                       err("init isoc: usb_submit_urb(%d) ret %d", n, err);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static void
-ov51x_unlink_isoc(struct usb_ov511 *ov)
-{
-       int n;
-
-       /* Unschedule all of the iso td's */
-       for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-               if (ov->sbuf[n].urb) {
-                       usb_kill_urb(ov->sbuf[n].urb);
-                       usb_free_urb(ov->sbuf[n].urb);
-                       ov->sbuf[n].urb = NULL;
-               }
-       }
-}
-
-static void
-ov51x_stop_isoc(struct usb_ov511 *ov)
-{
-       if (!ov->streaming || !ov->dev)
-               return;
-
-       PDEBUG(3, "*** Stopping capture ***");
-
-       if (ov->bclass == BCL_OV518)
-               ov518_set_packet_size(ov, 0);
-       else
-               ov511_set_packet_size(ov, 0);
-
-       ov->streaming = 0;
-
-       ov51x_unlink_isoc(ov);
-}
-
-static int
-ov51x_new_frame(struct usb_ov511 *ov, int framenum)
-{
-       struct ov511_frame *frame;
-       int newnum;
-
-       PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
-
-       if (!ov->dev)
-               return -1;
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /* ready to be grabbed into, then use it instead */
-       if (ov->curframe == -1) {
-               newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
-               if (ov->frame[newnum].grabstate == FRAME_READY)
-                       framenum = newnum;
-       } else
-               return 0;
-
-       frame = &ov->frame[framenum];
-
-       PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
-              frame->width, frame->height);
-
-       frame->grabstate = FRAME_GRABBING;
-       frame->scanstate = STATE_SCANNING;
-       frame->snapshot = 0;
-
-       ov->curframe = framenum;
-
-       /* Make sure it's not too big */
-       if (frame->width > ov->maxwidth)
-               frame->width = ov->maxwidth;
-
-       frame->width &= ~7L;            /* Multiple of 8 */
-
-       if (frame->height > ov->maxheight)
-               frame->height = ov->maxheight;
-
-       frame->height &= ~3L;           /* Multiple of 4 */
-
-       return 0;
-}
-
-/****************************************************************************
- *
- * Buffer management
- *
- ***************************************************************************/
-
-/*
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
-       int i;
-       PDEBUG(4, "entered");
-
-       if (ov->fbuf) {
-               rvfree(ov->fbuf, OV511_NUMFRAMES
-                      * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-               ov->fbuf = NULL;
-       }
-
-       vfree(ov->rawfbuf);
-       ov->rawfbuf = NULL;
-
-       vfree(ov->tempfbuf);
-       ov->tempfbuf = NULL;
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               kfree(ov->sbuf[i].data);
-               ov->sbuf[i].data = NULL;
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].data = NULL;
-               ov->frame[i].rawdata = NULL;
-               ov->frame[i].tempdata = NULL;
-               if (ov->frame[i].compbuf) {
-                       free_page((unsigned long) ov->frame[i].compbuf);
-                       ov->frame[i].compbuf = NULL;
-               }
-       }
-
-       PDEBUG(4, "buffer memory deallocated");
-       ov->buf_state = BUF_NOT_ALLOCATED;
-       PDEBUG(4, "leaving");
-}
-
-static int
-ov51x_alloc(struct usb_ov511 *ov)
-{
-       int i;
-       const int w = ov->maxwidth;
-       const int h = ov->maxheight;
-       const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
-       const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
-       PDEBUG(4, "entered");
-       mutex_lock(&ov->buf_lock);
-
-       if (ov->buf_state == BUF_ALLOCATED)
-               goto out;
-
-       ov->fbuf = rvmalloc(data_bufsize);
-       if (!ov->fbuf)
-               goto error;
-
-       ov->rawfbuf = vmalloc(raw_bufsize);
-       if (!ov->rawfbuf)
-               goto error;
-
-       memset(ov->rawfbuf, 0, raw_bufsize);
-
-       ov->tempfbuf = vmalloc(raw_bufsize);
-       if (!ov->tempfbuf)
-               goto error;
-
-       memset(ov->tempfbuf, 0, raw_bufsize);
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
-                       MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-               if (!ov->sbuf[i].data)
-                       goto error;
-
-               PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
-               ov->frame[i].rawdata = ov->rawfbuf
-                + i * MAX_RAW_DATA_SIZE(w, h);
-               ov->frame[i].tempdata = ov->tempfbuf
-                + i * MAX_RAW_DATA_SIZE(w, h);
-
-               ov->frame[i].compbuf =
-                (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!ov->frame[i].compbuf)
-                       goto error;
-
-               PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
-       }
-
-       ov->buf_state = BUF_ALLOCATED;
-out:
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "leaving");
-       return 0;
-error:
-       ov51x_do_dealloc(ov);
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "errored");
-       return -ENOMEM;
-}
-
-static void
-ov51x_dealloc(struct usb_ov511 *ov)
-{
-       PDEBUG(4, "entered");
-       mutex_lock(&ov->buf_lock);
-       ov51x_do_dealloc(ov);
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "leaving");
-}
-
-/****************************************************************************
- *
- * V4L 1 API
- *
- ***************************************************************************/
-
-static int
-ov51x_v4l1_open(struct inode *inode, struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int err, i;
-
-       PDEBUG(4, "opening");
-
-       mutex_lock(&ov->lock);
-
-       err = -EBUSY;
-       if (ov->user)
-               goto out;
-
-       ov->sub_flag = 0;
-
-       /* In case app doesn't set them... */
-       err = ov51x_set_default_params(ov);
-       if (err < 0)
-               goto out;
-
-       /* Make sure frames are reset */
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].grabstate = FRAME_UNUSED;
-               ov->frame[i].bytes_read = 0;
-       }
-
-       /* If compression is on, make sure now that a
-        * decompressor can be loaded */
-       if (ov->compress && !ov->decomp_ops) {
-               err = request_decompressor(ov);
-               if (err && !dumppix)
-                       goto out;
-       }
-
-       err = ov51x_alloc(ov);
-       if (err < 0)
-               goto out;
-
-       err = ov51x_init_isoc(ov);
-       if (err) {
-               ov51x_dealloc(ov);
-               goto out;
-       }
-
-       ov->user++;
-       file->private_data = vdev;
-
-       if (ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 1);
-
-out:
-       mutex_unlock(&ov->lock);
-       return err;
-}
-
-static int
-ov51x_v4l1_close(struct inode *inode, struct file *file)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-
-       PDEBUG(4, "ov511_close");
-
-       mutex_lock(&ov->lock);
-
-       ov->user--;
-       ov51x_stop_isoc(ov);
-
-       if (ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-
-       if (ov->dev)
-               ov51x_dealloc(ov);
-
-       mutex_unlock(&ov->lock);
-
-       /* Device unplugged while open. Only a minimum of unregistration is done
-        * here; the disconnect callback already did the rest. */
-       if (!ov->dev) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-
-               ov51x_dealloc(ov);
-               kfree(ov);
-               ov = NULL;
-       }
-
-       file->private_data = NULL;
-       return 0;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       PDEBUG(5, "IOCtl: 0x%X", cmd);
-
-       if (!ov->dev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *b = arg;
-
-               PDEBUG(4, "VIDIOCGCAP");
-
-               memset(b, 0, sizeof(struct video_capability));
-               sprintf(b->name, "%s USB Camera",
-                       symbolic(brglist, ov->bridge));
-               b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-               b->channels = ov->num_inputs;
-               b->audios = 0;
-               b->maxwidth = ov->maxwidth;
-               b->maxheight = ov->maxheight;
-               b->minwidth = ov->minwidth;
-               b->minheight = ov->minheight;
-
-               return 0;
-       }
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-
-               PDEBUG(4, "VIDIOCGCHAN");
-
-               if ((unsigned)(v->channel) >= ov->num_inputs) {
-                       err("Invalid channel (%d)", v->channel);
-                       return -EINVAL;
-               }
-
-               v->norm = ov->norm;
-               v->type = VIDEO_TYPE_CAMERA;
-               v->flags = 0;
-//             v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-               v->tuners = 0;
-               decoder_get_input_name(ov, v->channel, v->name);
-
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-               int err;
-
-               PDEBUG(4, "VIDIOCSCHAN");
-
-               /* Make sure it's not a camera */
-               if (!ov->has_decoder) {
-                       if (v->channel == 0)
-                               return 0;
-                       else
-                               return -EINVAL;
-               }
-
-               if (v->norm != VIDEO_MODE_PAL &&
-                   v->norm != VIDEO_MODE_NTSC &&
-                   v->norm != VIDEO_MODE_SECAM &&
-                   v->norm != VIDEO_MODE_AUTO) {
-                       err("Invalid norm (%d)", v->norm);
-                       return -EINVAL;
-               }
-
-               if ((unsigned)(v->channel) >= ov->num_inputs) {
-                       err("Invalid channel (%d)", v->channel);
-                       return -EINVAL;
-               }
-
-               err = decoder_set_input(ov, v->channel);
-               if (err)
-                       return err;
-
-               err = decoder_set_norm(ov, v->norm);
-               if (err)
-                       return err;
-
-               return 0;
-       }
-       case VIDIOCGPICT:
-       {
-               struct video_picture *p = arg;
-
-               PDEBUG(4, "VIDIOCGPICT");
-
-               memset(p, 0, sizeof(struct video_picture));
-               if (sensor_get_picture(ov, p))
-                       return -EIO;
-
-               /* Can we get these from frame[0]? -claudio? */
-               p->depth = ov->frame[0].depth;
-               p->palette = ov->frame[0].format;
-
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *p = arg;
-               int i, rc;
-
-               PDEBUG(4, "VIDIOCSPICT");
-
-               if (!get_depth(p->palette))
-                       return -EINVAL;
-
-               if (sensor_set_picture(ov, p))
-                       return -EIO;
-
-               if (force_palette && p->palette != force_palette) {
-                       info("Palette rejected (%s)",
-                            symbolic(v4l1_plist, p->palette));
-                       return -EINVAL;
-               }
-
-               // FIXME: Format should be independent of frames
-               if (p->palette != ov->frame[0].format) {
-                       PDEBUG(4, "Detected format change");
-
-                       rc = ov51x_wait_frames_inactive(ov);
-                       if (rc)
-                               return rc;
-
-                       mode_init_regs(ov, ov->frame[0].width,
-                               ov->frame[0].height, p->palette, ov->sub_flag);
-               }
-
-               PDEBUG(4, "Setting depth=%d, palette=%s",
-                      p->depth, symbolic(v4l1_plist, p->palette));
-
-               for (i = 0; i < OV511_NUMFRAMES; i++) {
-                       ov->frame[i].depth = p->depth;
-                       ov->frame[i].format = p->palette;
-               }
-
-               return 0;
-       }
-       case VIDIOCGCAPTURE:
-       {
-               int *vf = arg;
-
-               PDEBUG(4, "VIDIOCGCAPTURE");
-
-               ov->sub_flag = *vf;
-               return 0;
-       }
-       case VIDIOCSCAPTURE:
-       {
-               struct video_capture *vc = arg;
-
-               PDEBUG(4, "VIDIOCSCAPTURE");
-
-               if (vc->flags)
-                       return -EINVAL;
-               if (vc->decimation)
-                       return -EINVAL;
-
-               vc->x &= ~3L;
-               vc->y &= ~1L;
-               vc->y &= ~31L;
-
-               if (vc->width == 0)
-                       vc->width = 32;
-
-               vc->height /= 16;
-               vc->height *= 16;
-               if (vc->height == 0)
-                       vc->height = 16;
-
-               ov->subx = vc->x;
-               ov->suby = vc->y;
-               ov->subw = vc->width;
-               ov->subh = vc->height;
-
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *vw = arg;
-               int i, rc;
-
-               PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
-
-#if 0
-               if (vw->flags)
-                       return -EINVAL;
-               if (vw->clipcount)
-                       return -EINVAL;
-               if (vw->height != ov->maxheight)
-                       return -EINVAL;
-               if (vw->width != ov->maxwidth)
-                       return -EINVAL;
-#endif
-
-               rc = ov51x_wait_frames_inactive(ov);
-               if (rc)
-                       return rc;
-
-               rc = mode_init_regs(ov, vw->width, vw->height,
-                       ov->frame[0].format, ov->sub_flag);
-               if (rc < 0)
-                       return rc;
-
-               for (i = 0; i < OV511_NUMFRAMES; i++) {
-                       ov->frame[i].width = vw->width;
-                       ov->frame[i].height = vw->height;
-               }
-
-               return 0;
-       }
-       case VIDIOCGWIN:
-       {
-               struct video_window *vw = arg;
-
-               memset(vw, 0, sizeof(struct video_window));
-               vw->x = 0;              /* FIXME */
-               vw->y = 0;
-               vw->width = ov->frame[0].width;
-               vw->height = ov->frame[0].height;
-               vw->flags = 30;
-
-               PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
-
-               return 0;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vm = arg;
-               int i;
-
-               PDEBUG(4, "VIDIOCGMBUF");
-
-               memset(vm, 0, sizeof(struct video_mbuf));
-               vm->size = OV511_NUMFRAMES
-                          * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-               vm->frames = OV511_NUMFRAMES;
-
-               vm->offsets[0] = 0;
-               for (i = 1; i < OV511_NUMFRAMES; i++) {
-                       vm->offsets[i] = vm->offsets[i-1]
-                          + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-               }
-
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-               int rc, depth;
-               unsigned int f = vm->frame;
-
-               PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
-                       vm->height, symbolic(v4l1_plist, vm->format));
-
-               depth = get_depth(vm->format);
-               if (!depth) {
-                       PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
-                              symbolic(v4l1_plist, vm->format));
-                       return -EINVAL;
-               }
-
-               if (f >= OV511_NUMFRAMES) {
-                       err("VIDIOCMCAPTURE: invalid frame (%d)", f);
-                       return -EINVAL;
-               }
-
-               if (vm->width > ov->maxwidth
-                   || vm->height > ov->maxheight) {
-                       err("VIDIOCMCAPTURE: requested dimensions too big");
-                       return -EINVAL;
-               }
-
-               if (ov->frame[f].grabstate == FRAME_GRABBING) {
-                       PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
-                       return -EBUSY;
-               }
-
-               if (force_palette && (vm->format != force_palette)) {
-                       PDEBUG(2, "palette rejected (%s)",
-                              symbolic(v4l1_plist, vm->format));
-                       return -EINVAL;
-               }
-
-               if ((ov->frame[f].width != vm->width) ||
-                   (ov->frame[f].height != vm->height) ||
-                   (ov->frame[f].format != vm->format) ||
-                   (ov->frame[f].sub_flag != ov->sub_flag) ||
-                   (ov->frame[f].depth != depth)) {
-                       PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
-
-                       rc = ov51x_wait_frames_inactive(ov);
-                       if (rc)
-                               return rc;
-
-                       rc = mode_init_regs(ov, vm->width, vm->height,
-                               vm->format, ov->sub_flag);
-#if 0
-                       if (rc < 0) {
-                               PDEBUG(1, "Got error while initializing regs ");
-                               return ret;
-                       }
-#endif
-                       ov->frame[f].width = vm->width;
-                       ov->frame[f].height = vm->height;
-                       ov->frame[f].format = vm->format;
-                       ov->frame[f].sub_flag = ov->sub_flag;
-                       ov->frame[f].depth = depth;
-               }
-
-               /* Mark it as ready */
-               ov->frame[f].grabstate = FRAME_READY;
-
-               PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
-
-               return ov51x_new_frame(ov, f);
-       }
-       case VIDIOCSYNC:
-       {
-               unsigned int fnum = *((unsigned int *) arg);
-               struct ov511_frame *frame;
-               int rc;
-
-               if (fnum >= OV511_NUMFRAMES) {
-                       err("VIDIOCSYNC: invalid frame (%d)", fnum);
-                       return -EINVAL;
-               }
-
-               frame = &ov->frame[fnum];
-
-               PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
-                      frame->grabstate);
-
-               switch (frame->grabstate) {
-               case FRAME_UNUSED:
-                       return -EINVAL;
-               case FRAME_READY:
-               case FRAME_GRABBING:
-               case FRAME_ERROR:
-redo:
-                       if (!ov->dev)
-                               return -EIO;
-
-                       rc = wait_event_interruptible(frame->wq,
-                           (frame->grabstate == FRAME_DONE)
-                           || (frame->grabstate == FRAME_ERROR));
-
-                       if (rc)
-                               return rc;
-
-                       if (frame->grabstate == FRAME_ERROR) {
-                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-                                       return rc;
-                               goto redo;
-                       }
-                       /* Fall through */
-               case FRAME_DONE:
-                       if (ov->snap_enabled && !frame->snapshot) {
-                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-                                       return rc;
-                               goto redo;
-                       }
-
-                       frame->grabstate = FRAME_UNUSED;
-
-                       /* Reset the hardware snapshot button */
-                       /* FIXME - Is this the best place for this? */
-                       if ((ov->snap_enabled) && (frame->snapshot)) {
-                               frame->snapshot = 0;
-                               ov51x_clear_snapshot(ov);
-                       }
-
-                       /* Decompression, format conversion, etc... */
-                       ov51x_postprocess(ov, frame);
-
-                       break;
-               } /* end switch */
-
-               return 0;
-       }
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vb = arg;
-
-               PDEBUG(4, "VIDIOCGFBUF");
-
-               memset(vb, 0, sizeof(struct video_buffer));
-
-               return 0;
-       }
-       case VIDIOCGUNIT:
-       {
-               struct video_unit *vu = arg;
-
-               PDEBUG(4, "VIDIOCGUNIT");
-
-               memset(vu, 0, sizeof(struct video_unit));
-
-               vu->video = ov->vdev->minor;
-               vu->vbi = VIDEO_NO_UNIT;
-               vu->radio = VIDEO_NO_UNIT;
-               vu->audio = VIDEO_NO_UNIT;
-               vu->teletext = VIDEO_NO_UNIT;
-
-               return 0;
-       }
-       case OV511IOC_WI2C:
-       {
-               struct ov511_i2c_struct *w = arg;
-
-               return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
-       }
-       case OV511IOC_RI2C:
-       {
-               struct ov511_i2c_struct *r = arg;
-               int rc;
-
-               rc = i2c_r_slave(ov, r->slave, r->reg);
-               if (rc < 0)
-                       return rc;
-
-               r->value = rc;
-               return 0;
-       }
-       default:
-               PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-               return -ENOIOCTLCMD;
-       } /* end switch */
-
-       return 0;
-}
-
-static int
-ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
-                unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int rc;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
-
-       mutex_unlock(&ov->lock);
-       return rc;
-}
-
-static ssize_t
-ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
-{
-       struct video_device *vdev = file->private_data;
-       int noblock = file->f_flags&O_NONBLOCK;
-       unsigned long count = cnt;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int i, rc = 0, frmx = -1;
-       struct ov511_frame *frame;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
-
-       if (!vdev || !buf) {
-               rc = -EFAULT;
-               goto error;
-       }
-
-       if (!ov->dev) {
-               rc = -EIO;
-               goto error;
-       }
-
-// FIXME: Only supports two frames
-       /* See if a frame is completed, then use it. */
-       if (ov->frame[0].grabstate >= FRAME_DONE)       /* _DONE or _ERROR */
-               frmx = 0;
-       else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-               frmx = 1;
-
-       /* If nonblocking we return immediately */
-       if (noblock && (frmx == -1)) {
-               rc = -EAGAIN;
-               goto error;
-       }
-
-       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
-       /* See if a frame is in process (grabbing), then use it. */
-       if (frmx == -1) {
-               if (ov->frame[0].grabstate == FRAME_GRABBING)
-                       frmx = 0;
-               else if (ov->frame[1].grabstate == FRAME_GRABBING)
-                       frmx = 1;
-       }
-
-       /* If no frame is active, start one. */
-       if (frmx == -1) {
-               if ((rc = ov51x_new_frame(ov, frmx = 0))) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-       }
-
-       frame = &ov->frame[frmx];
-
-restart:
-       if (!ov->dev) {
-               rc = -EIO;
-               goto error;
-       }
-
-       /* Wait while we're grabbing the image */
-       PDEBUG(4, "Waiting image grabbing");
-       rc = wait_event_interruptible(frame->wq,
-               (frame->grabstate == FRAME_DONE)
-               || (frame->grabstate == FRAME_ERROR));
-
-       if (rc)
-               goto error;
-
-       PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
-       PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
-
-       if (frame->grabstate == FRAME_ERROR) {
-               frame->bytes_read = 0;
-               err("** ick! ** Errored frame %d", ov->curframe);
-               if (ov51x_new_frame(ov, frmx)) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-               goto restart;
-       }
-
-
-       /* Repeat until we get a snapshot frame */
-       if (ov->snap_enabled)
-               PDEBUG(4, "Waiting snapshot frame");
-       if (ov->snap_enabled && !frame->snapshot) {
-               frame->bytes_read = 0;
-               if ((rc = ov51x_new_frame(ov, frmx))) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-               goto restart;
-       }
-
-       /* Clear the snapshot */
-       if (ov->snap_enabled && frame->snapshot) {
-               frame->snapshot = 0;
-               ov51x_clear_snapshot(ov);
-       }
-
-       /* Decompression, format conversion, etc... */
-       ov51x_postprocess(ov, frame);
-
-       PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
-               frame->bytes_read,
-               get_frame_length(frame));
-
-       /* copy bytes to user space; we allow for partials reads */
-//     if ((count + frame->bytes_read)
-//         > get_frame_length((struct ov511_frame *)frame))
-//             count = frame->scanlength - frame->bytes_read;
-
-       /* FIXME - count hardwired to be one frame... */
-       count = get_frame_length(frame);
-
-       PDEBUG(4, "Copy to user space: %ld bytes", count);
-       if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
-               PDEBUG(4, "Copy failed! %d bytes not copied", i);
-               rc = -EFAULT;
-               goto error;
-       }
-
-       frame->bytes_read += count;
-       PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
-               count, frame->bytes_read);
-
-       /* If all data have been read... */
-       if (frame->bytes_read
-           >= get_frame_length(frame)) {
-               frame->bytes_read = 0;
-
-// FIXME: Only supports two frames
-               /* Mark it as available to be used again. */
-               ov->frame[frmx].grabstate = FRAME_UNUSED;
-               if ((rc = ov51x_new_frame(ov, !frmx))) {
-                       err("ov51x_new_frame returned error");
-                       goto error;
-               }
-       }
-
-       PDEBUG(4, "read finished, returning %ld (sweet)", count);
-
-       mutex_unlock(&ov->lock);
-       return count;
-
-error:
-       mutex_unlock(&ov->lock);
-       return rc;
-}
-
-static int
-ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *vdev = file->private_data;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end - vma->vm_start;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       unsigned long page, pos;
-
-       if (ov->dev == NULL)
-               return -EIO;
-
-       PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
-
-       if (size > (((OV511_NUMFRAMES
-                     * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
-                     + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       pos = (unsigned long)ov->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&ov->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       mutex_unlock(&ov->lock);
-       return 0;
-}
-
-static struct file_operations ov511_fops = {
-       .owner =        THIS_MODULE,
-       .open =         ov51x_v4l1_open,
-       .release =      ov51x_v4l1_close,
-       .read =         ov51x_v4l1_read,
-       .mmap =         ov51x_v4l1_mmap,
-       .ioctl =        ov51x_v4l1_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-
-static struct video_device vdev_template = {
-       .owner =        THIS_MODULE,
-       .name =         "OV511 USB Camera",
-       .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_OV511,
-       .fops =         &ov511_fops,
-       .release =      video_device_release,
-       .minor =        -1,
-};
-
-/****************************************************************************
- *
- * OV511 and sensor configuration
- *
- ***************************************************************************/
-
-/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
- * the same register settings as the OV7610, since they are very similar.
- */
-static int
-ov7xx0_configure(struct usb_ov511 *ov)
-{
-       int i, success;
-       int rc;
-
-       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
-        *
-        * Register 0x0f in the 7610 has the following effects:
-        *
-        * 0x85 (AEC method 1): Best overall, good contrast range
-        * 0x45 (AEC method 2): Very overexposed
-        * 0xa5 (spec sheet default): Ok, but the black level is
-        *      shifted resulting in loss of contrast
-        * 0x05 (old driver setting): very overexposed, too much
-        *      contrast
-        */
-       static struct ov511_regvals aRegvalsNorm7610[] = {
-               { OV511_I2C_BUS, 0x10, 0xff },
-               { OV511_I2C_BUS, 0x16, 0x06 },
-               { OV511_I2C_BUS, 0x28, 0x24 },
-               { OV511_I2C_BUS, 0x2b, 0xac },
-               { OV511_I2C_BUS, 0x12, 0x00 },
-               { OV511_I2C_BUS, 0x38, 0x81 },
-               { OV511_I2C_BUS, 0x28, 0x24 },  /* 0c */
-               { OV511_I2C_BUS, 0x0f, 0x85 },  /* lg's setting */
-               { OV511_I2C_BUS, 0x15, 0x01 },
-               { OV511_I2C_BUS, 0x20, 0x1c },
-               { OV511_I2C_BUS, 0x23, 0x2a },
-               { OV511_I2C_BUS, 0x24, 0x10 },
-               { OV511_I2C_BUS, 0x25, 0x8a },
-               { OV511_I2C_BUS, 0x26, 0xa2 },
-               { OV511_I2C_BUS, 0x27, 0xc2 },
-               { OV511_I2C_BUS, 0x2a, 0x04 },
-               { OV511_I2C_BUS, 0x2c, 0xfe },
-               { OV511_I2C_BUS, 0x2d, 0x93 },
-               { OV511_I2C_BUS, 0x30, 0x71 },
-               { OV511_I2C_BUS, 0x31, 0x60 },
-               { OV511_I2C_BUS, 0x32, 0x26 },
-               { OV511_I2C_BUS, 0x33, 0x20 },
-               { OV511_I2C_BUS, 0x34, 0x48 },
-               { OV511_I2C_BUS, 0x12, 0x24 },
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm7620[] = {
-               { OV511_I2C_BUS, 0x00, 0x00 },
-               { OV511_I2C_BUS, 0x01, 0x80 },
-               { OV511_I2C_BUS, 0x02, 0x80 },
-               { OV511_I2C_BUS, 0x03, 0xc0 },
-               { OV511_I2C_BUS, 0x06, 0x60 },
-               { OV511_I2C_BUS, 0x07, 0x00 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x12, 0x24 },
-               { OV511_I2C_BUS, 0x13, 0x01 },
-               { OV511_I2C_BUS, 0x14, 0x84 },
-               { OV511_I2C_BUS, 0x15, 0x01 },
-               { OV511_I2C_BUS, 0x16, 0x03 },
-               { OV511_I2C_BUS, 0x17, 0x2f },
-               { OV511_I2C_BUS, 0x18, 0xcf },
-               { OV511_I2C_BUS, 0x19, 0x06 },
-               { OV511_I2C_BUS, 0x1a, 0xf5 },
-               { OV511_I2C_BUS, 0x1b, 0x00 },
-               { OV511_I2C_BUS, 0x20, 0x18 },
-               { OV511_I2C_BUS, 0x21, 0x80 },
-               { OV511_I2C_BUS, 0x22, 0x80 },
-               { OV511_I2C_BUS, 0x23, 0x00 },
-               { OV511_I2C_BUS, 0x26, 0xa2 },
-               { OV511_I2C_BUS, 0x27, 0xea },
-               { OV511_I2C_BUS, 0x28, 0x20 },
-               { OV511_I2C_BUS, 0x29, 0x00 },
-               { OV511_I2C_BUS, 0x2a, 0x10 },
-               { OV511_I2C_BUS, 0x2b, 0x00 },
-               { OV511_I2C_BUS, 0x2c, 0x88 },
-               { OV511_I2C_BUS, 0x2d, 0x91 },
-               { OV511_I2C_BUS, 0x2e, 0x80 },
-               { OV511_I2C_BUS, 0x2f, 0x44 },
-               { OV511_I2C_BUS, 0x60, 0x27 },
-               { OV511_I2C_BUS, 0x61, 0x02 },
-               { OV511_I2C_BUS, 0x62, 0x5f },
-               { OV511_I2C_BUS, 0x63, 0xd5 },
-               { OV511_I2C_BUS, 0x64, 0x57 },
-               { OV511_I2C_BUS, 0x65, 0x83 },
-               { OV511_I2C_BUS, 0x66, 0x55 },
-               { OV511_I2C_BUS, 0x67, 0x92 },
-               { OV511_I2C_BUS, 0x68, 0xcf },
-               { OV511_I2C_BUS, 0x69, 0x76 },
-               { OV511_I2C_BUS, 0x6a, 0x22 },
-               { OV511_I2C_BUS, 0x6b, 0x00 },
-               { OV511_I2C_BUS, 0x6c, 0x02 },
-               { OV511_I2C_BUS, 0x6d, 0x44 },
-               { OV511_I2C_BUS, 0x6e, 0x80 },
-               { OV511_I2C_BUS, 0x6f, 0x1d },
-               { OV511_I2C_BUS, 0x70, 0x8b },
-               { OV511_I2C_BUS, 0x71, 0x00 },
-               { OV511_I2C_BUS, 0x72, 0x14 },
-               { OV511_I2C_BUS, 0x73, 0x54 },
-               { OV511_I2C_BUS, 0x74, 0x00 },
-               { OV511_I2C_BUS, 0x75, 0x8e },
-               { OV511_I2C_BUS, 0x76, 0x00 },
-               { OV511_I2C_BUS, 0x77, 0xff },
-               { OV511_I2C_BUS, 0x78, 0x80 },
-               { OV511_I2C_BUS, 0x79, 0x80 },
-               { OV511_I2C_BUS, 0x7a, 0x80 },
-               { OV511_I2C_BUS, 0x7b, 0xe2 },
-               { OV511_I2C_BUS, 0x7c, 0x00 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "starting configuration");
-
-       /* This looks redundant, but is necessary for WebCam 3 */
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               return -1;
-
-       if (init_ov_sensor(ov) >= 0) {
-               PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
-       } else {
-               /* Reset the 76xx */
-               if (i2c_w(ov, 0x12, 0x80) < 0)
-                       return -1;
-
-               /* Wait for it to initialize */
-               msleep(150);
-
-               i = 0;
-               success = 0;
-               while (i <= i2c_detect_tries) {
-                       if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-                           (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-                               success = 1;
-                               break;
-                       } else {
-                               i++;
-                       }
-               }
-
-// Was (i == i2c_detect_tries) previously. This obviously used to always report
-// success. Whether anyone actually depended on that bug is unknown
-               if ((i >= i2c_detect_tries) && (success == 0)) {
-                       err("Failed to read sensor ID. You might not have an");
-                       err("OV7610/20, or it may be not responding. Report");
-                       err("this to " EMAIL);
-                       err("This is only a warning. You can attempt to use");
-                       err("your camera anyway");
-// Only issue a warning for now
-//                     return -1;
-               } else {
-                       PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
-               }
-       }
-
-       /* Detect sensor (sub)type */
-       rc = i2c_r(ov, OV7610_REG_COM_I);
-
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       } else if ((rc & 3) == 3) {
-               info("Sensor is an OV7610");
-               ov->sensor = SEN_OV7610;
-       } else if ((rc & 3) == 1) {
-               /* I don't know what's different about the 76BE yet. */
-               if (i2c_r(ov, 0x15) & 1)
-                       info("Sensor is an OV7620AE");
-               else
-                       info("Sensor is an OV76BE");
-
-               /* OV511+ will return all zero isoc data unless we
-                * configure the sensor as a 7620. Someone needs to
-                * find the exact reg. setting that causes this. */
-               if (ov->bridge == BRG_OV511PLUS) {
-                       info("Enabling 511+/7620AE workaround");
-                       ov->sensor = SEN_OV7620;
-               } else {
-                       ov->sensor = SEN_OV76BE;
-               }
-       } else if ((rc & 3) == 0) {
-               info("Sensor is an OV7620");
-               ov->sensor = SEN_OV7620;
-       } else {
-               err("Unknown image sensor version: %d", rc & 3);
-               return -1;
-       }
-
-       if (ov->sensor == SEN_OV7620) {
-               PDEBUG(4, "Writing 7620 registers");
-               if (write_regvals(ov, aRegvalsNorm7620))
-                       return -1;
-       } else {
-               PDEBUG(4, "Writing 7610 registers");
-               if (write_regvals(ov, aRegvalsNorm7610))
-                       return -1;
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 640;
-       ov->maxheight = 480;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       return 0;
-}
-
-/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
-ov6xx0_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-       static struct ov511_regvals aRegvalsNorm6x20[] = {
-               { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x03, 0x60 },
-               { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-               { OV511_I2C_BUS, 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
-               { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
-               { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
-               { OV511_I2C_BUS, 0x14, 0x04 },
-               /* 0x16: 0x06 helps frame stability with moving objects */
-               { OV511_I2C_BUS, 0x16, 0x06 },
-//             { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-               { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-               { OV511_I2C_BUS, 0x28, 0x05 },
-               { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//             { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-               { OV511_I2C_BUS, 0x2d, 0x99 },
-               { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
-               { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
-               { OV511_I2C_BUS, 0x38, 0x8b },
-               { OV511_I2C_BUS, 0x39, 0x40 },
-
-               { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-               { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-               { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-               { OV511_I2C_BUS, 0x3d, 0x80 },
-               /* These next two registers (0x4a, 0x4b) are undocumented. They
-                * control the color balance */
-               { OV511_I2C_BUS, 0x4a, 0x80 },
-               { OV511_I2C_BUS, 0x4b, 0x80 },
-               { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
-               { OV511_I2C_BUS, 0x4e, 0xc1 },
-               { OV511_I2C_BUS, 0x4f, 0x04 },
-// Do 50-53 have any effect?
-// Toggle 0x12[2] off and on here?
-               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
-       };
-
-       static struct ov511_regvals aRegvalsNorm6x30[] = {
-       /*OK*/  { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-               { OV511_I2C_BUS, 0x11, 0x00 },
-       /*OK*/  { OV511_I2C_BUS, 0x03, 0x60 },
-       /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-               { OV511_I2C_BUS, 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-       /*OK*/  { OV511_I2C_BUS, 0x0c, 0x24 },
-       /*OK*/  { OV511_I2C_BUS, 0x0d, 0x24 },
-       /*A*/   { OV511_I2C_BUS, 0x0e, 0x20 },
-//     /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
-               { OV511_I2C_BUS, 0x16, 0x03 },
-//     /*OK*/  { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-               // 21 & 22? The suggested values look wrong. Go with default
-       /*A*/   { OV511_I2C_BUS, 0x23, 0xc0 },
-       /*A*/   { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-//     /*OK*/  { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
-//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
-
-       /*OK*/  { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//     /*OK*/  { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-               { OV511_I2C_BUS, 0x2d, 0x99 },
-//     /*A*/   { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-//     /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-//     /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
-//     /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
-//             { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-//             { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-//             { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-               { OV511_I2C_BUS, 0x3d, 0x80 },
-//     /*A*/   { OV511_I2C_BUS, 0x3f, 0x0e },
-
-               /* These next two registers (0x4a, 0x4b) are undocumented. They
-                * control the color balance */
-//     /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-//     /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
-               { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-       /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
-
-               /* UV average mode, color killer: strongest */
-               { OV511_I2C_BUS, 0x4f, 0x07 },
-
-               { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
-               { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
-               { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
-               { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
-               { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
-//             { OV511_I2C_BUS, 0x5c, 0x10 },
-               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
-       };
-
-       PDEBUG(4, "starting sensor configuration");
-
-       if (init_ov_sensor(ov) < 0) {
-               err("Failed to read sensor ID. You might not have an OV6xx0,");
-               err("or it may be not responding. Report this to " EMAIL);
-               return -1;
-       } else {
-               PDEBUG(1, "OV6xx0 sensor detected");
-       }
-
-       /* Detect sensor (sub)type */
-       rc = i2c_r(ov, OV7610_REG_COM_I);
-
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       }
-
-       if ((rc & 3) == 0) {
-               ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630");
-       } else if ((rc & 3) == 1) {
-               ov->sensor = SEN_OV6620;
-               info("Sensor is an OV6620");
-       } else if ((rc & 3) == 2) {
-               ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630AE");
-       } else if ((rc & 3) == 3) {
-               ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630AF");
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 352;
-       ov->maxheight = 288;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       if (ov->sensor == SEN_OV6620) {
-               PDEBUG(4, "Writing 6x20 registers");
-               if (write_regvals(ov, aRegvalsNorm6x20))
-                       return -1;
-       } else {
-               PDEBUG(4, "Writing 6x30 registers");
-               if (write_regvals(ov, aRegvalsNorm6x30))
-                       return -1;
-       }
-
-       return 0;
-}
-
-/* This initializes the KS0127 and KS0127B video decoders. */
-static int 
-ks0127_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-       if (ov51x_init_ks_sensor(ov) < 0) {
-               err("Failed to initialize the KS0127");
-               return -1;
-       } else {
-               PDEBUG(1, "KS012x(B) sensor detected");
-       }
-#endif
-
-       /* Detect decoder subtype */
-       rc = i2c_r(ov, 0x00);
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       } else if (rc & 0x08) {
-               rc = i2c_r(ov, 0x3d);
-               if (rc < 0) {
-                       err("Error detecting sensor type");
-                       return -1;
-               } else if ((rc & 0x0f) == 0) {
-                       info("Sensor is a KS0127");
-                       ov->sensor = SEN_KS0127;
-               } else if ((rc & 0x0f) == 9) {
-                       info("Sensor is a KS0127B Rev. A");
-                       ov->sensor = SEN_KS0127B;
-               }
-       } else {
-               err("Error: Sensor is an unsupported KS0122");
-               return -1;
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 640;
-       ov->maxheight = 480;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       /* This device is not supported yet. Bail out now... */
-       err("This sensor is not supported yet.");
-       return -1;
-
-       return 0;
-}
-
-/* This initializes the SAA7111A video decoder. */
-static int
-saa7111a_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-       /* Since there is no register reset command, all registers must be
-        * written, otherwise gives erratic results */
-       static struct ov511_regvals aRegvalsNormSAA7111A[] = {
-               { OV511_I2C_BUS, 0x06, 0xce },
-               { OV511_I2C_BUS, 0x07, 0x00 },
-               { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
-               { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
-               { OV511_I2C_BUS, 0x00, 0x00 },
-               { OV511_I2C_BUS, 0x01, 0x00 },
-               { OV511_I2C_BUS, 0x03, 0x23 },
-               { OV511_I2C_BUS, 0x04, 0x00 },
-               { OV511_I2C_BUS, 0x05, 0x00 },
-               { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
-               { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
-               { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
-               { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
-               { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
-               { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
-               { OV511_I2C_BUS, 0x0f, 0x00 },
-               { OV511_I2C_BUS, 0x11, 0x0c },
-               { OV511_I2C_BUS, 0x12, 0x00 },
-               { OV511_I2C_BUS, 0x13, 0x00 },
-               { OV511_I2C_BUS, 0x14, 0x00 },
-               { OV511_I2C_BUS, 0x15, 0x00 },
-               { OV511_I2C_BUS, 0x16, 0x00 },
-               { OV511_I2C_BUS, 0x17, 0x00 },
-               { OV511_I2C_BUS, 0x02, 0xc0 },  /* Composite input 0 */
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-       if (ov51x_init_saa_sensor(ov) < 0) {
-               err("Failed to initialize the SAA7111A");
-               return -1;
-       } else {
-               PDEBUG(1, "SAA7111A sensor detected");
-       }
-#endif
-
-       /* 640x480 not supported with PAL */
-       if (ov->pal) {
-               ov->maxwidth = 320;
-               ov->maxheight = 240;            /* Even field only */
-       } else {
-               ov->maxwidth = 640;
-               ov->maxheight = 480;            /* Even/Odd fields */
-       }
-
-       ov->minwidth = 320;
-       ov->minheight = 240;            /* Even field only */
-
-       ov->has_decoder = 1;
-       ov->num_inputs = 8;
-       ov->norm = VIDEO_MODE_AUTO;
-       ov->stop_during_set = 0;        /* Decoder guarantees stable image */
-
-       /* Decoder doesn't change these values, so we use these instead of
-        * acutally reading the registers (which doesn't work) */
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x40 << 9;
-       ov->colour = 0x40 << 9;
-       ov->hue = 32768;
-
-       PDEBUG(4, "Writing SAA7111A registers");
-       if (write_regvals(ov, aRegvalsNormSAA7111A))
-               return -1;
-
-       /* Detect version of decoder. This must be done after writing the
-         * initial regs or the decoder will lock up. */
-       rc = i2c_r(ov, 0x00);
-
-       if (rc < 0) {
-               err("Error detecting sensor version");
-               return -1;
-       } else {
-               info("Sensor is an SAA7111A (version 0x%x)", rc);
-               ov->sensor = SEN_SAA7111A;
-       }
-
-       // FIXME: Fix this for OV518(+)
-       /* Latch to negative edge of clock. Otherwise, we get incorrect
-        * colors and jitter in the digital signal. */
-       if (ov->bclass == BCL_OV511)
-               reg_w(ov, 0x11, 0x00);
-       else
-               warn("SAA7111A not yet supported with OV518/OV518+");
-
-       return 0;
-}
-
-/* This initializes the OV511/OV511+ and the sensor */
-static int 
-ov511_configure(struct usb_ov511 *ov)
-{
-       static struct ov511_regvals aRegvalsInit511[] = {
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3d },
-               { OV511_DONE_BUS, 0x0, 0x00},
-       };
-
-       static struct ov511_regvals aRegvalsNorm511[] = {
-               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0x01 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R511_FIFO_OPTS,        0x1f },
-               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
-               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm511Plus[] = {
-               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0xff },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R511_FIFO_OPTS,        0xff },
-               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
-               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "");
-
-       ov->customid = reg_r(ov, R511_SYS_CUST_ID);
-       if (ov->customid < 0) {
-               err("Unable to read camera bridge registers");
-               goto error;
-       }
-
-       PDEBUG (1, "CustomID = %d", ov->customid);
-       ov->desc = symbolic(camlist, ov->customid);
-       info("model: %s", ov->desc);
-
-       if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
-               err("Camera type (%d) not recognized", ov->customid);
-               err("Please notify " EMAIL " of the name,");
-               err("manufacturer, model, and this number of your camera.");
-               err("Also include the output of the detection process.");
-       } 
-
-       if (ov->customid == 70)         /* USB Life TV (PAL/SECAM) */
-               ov->pal = 1;
-
-       if (write_regvals(ov, aRegvalsInit511))
-               goto error;
-
-       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-
-       /* The OV511+ has undocumented bits in the flow control register.
-        * Setting it to 0xff fixes the corruption with moving objects. */
-       if (ov->bridge == BRG_OV511) {
-               if (write_regvals(ov, aRegvalsNorm511))
-                       goto error;
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (write_regvals(ov, aRegvalsNorm511Plus))
-                       goto error;
-       } else {
-               err("Invalid bridge");
-       }
-
-       if (ov511_init_compression(ov))
-               goto error;
-
-       ov->packet_numbering = 1;
-       ov511_set_packet_size(ov, 0);
-
-       ov->snap_enabled = snapshot;
-
-       /* Test for 7xx0 */
-       PDEBUG(3, "Testing for 0V7xx0");
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               goto error;
-
-       if (i2c_w(ov, 0x12, 0x80) < 0) {
-               /* Test for 6xx0 */
-               PDEBUG(3, "Testing for 0V6xx0");
-               ov->primary_i2c_slave = OV6xx0_SID;
-               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-                       goto error;
-
-               if (i2c_w(ov, 0x12, 0x80) < 0) {
-                       /* Test for 8xx0 */
-                       PDEBUG(3, "Testing for 0V8xx0");
-                       ov->primary_i2c_slave = OV8xx0_SID;
-                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-                               goto error;
-
-                       if (i2c_w(ov, 0x12, 0x80) < 0) {
-                               /* Test for SAA7111A */
-                               PDEBUG(3, "Testing for SAA7111A");
-                               ov->primary_i2c_slave = SAA7111A_SID;
-                               if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
-                                       goto error;
-
-                               if (i2c_w(ov, 0x0d, 0x00) < 0) {
-                                       /* Test for KS0127 */
-                                       PDEBUG(3, "Testing for KS0127");
-                                       ov->primary_i2c_slave = KS0127_SID;
-                                       if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
-                                               goto error;
-
-                                       if (i2c_w(ov, 0x10, 0x00) < 0) {
-                                               err("Can't determine sensor slave IDs");
-                                               goto error;
-                                       } else {
-                                               if (ks0127_configure(ov) < 0) {
-                                                       err("Failed to configure KS0127");
-                                                       goto error;
-                                               }
-                                       }
-                               } else {
-                                       if (saa7111a_configure(ov) < 0) {
-                                               err("Failed to configure SAA7111A");
-                                               goto error;
-                                       }
-                               }
-                       } else {
-                               err("Detected unsupported OV8xx0 sensor");
-                               goto error;
-                       }
-               } else {
-                       if (ov6xx0_configure(ov) < 0) {
-                               err("Failed to configure OV6xx0");
-                               goto error;
-                       }
-               }
-       } else {
-               if (ov7xx0_configure(ov) < 0) {
-                       err("Failed to configure OV7xx0");
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       err("OV511 Config failed");
-
-       return -EBUSY;
-}
-
-/* This initializes the OV518/OV518+ and the sensor */
-static int
-ov518_configure(struct usb_ov511 *ov)
-{
-       /* For 518 and 518+ */
-       static struct ov511_regvals aRegvalsInit518[] = {
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x40 },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3e },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x00 },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, 0x46,                  0x00 }, 
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00},
-       };
-
-       static struct ov511_regvals aRegvalsNorm518[] = {
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
-               { OV511_REG_BUS, 0x31,                  0x0f },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_REG_BUS, 0x24,                  0x9f },
-               { OV511_REG_BUS, 0x25,                  0x90 },
-               { OV511_REG_BUS, 0x20,                  0x00 },
-               { OV511_REG_BUS, 0x51,                  0x04 },
-               { OV511_REG_BUS, 0x71,                  0x19 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm518Plus[] = {
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
-               { OV511_REG_BUS, 0x31,                  0x0f },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_REG_BUS, 0x24,                  0x9f },
-               { OV511_REG_BUS, 0x25,                  0x90 },
-               { OV511_REG_BUS, 0x20,                  0x60 },
-               { OV511_REG_BUS, 0x51,                  0x02 },
-               { OV511_REG_BUS, 0x71,                  0x19 },
-               { OV511_REG_BUS, 0x40,                  0xff },
-               { OV511_REG_BUS, 0x41,                  0x42 },
-               { OV511_REG_BUS, 0x46,                  0x00 },
-               { OV511_REG_BUS, 0x33,                  0x04 },
-               { OV511_REG_BUS, 0x21,                  0x19 },
-               { OV511_REG_BUS, 0x3f,                  0x10 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "");
-
-       /* First 5 bits of custom ID reg are a revision ID on OV518 */
-       info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
-
-       /* Give it the default description */
-       ov->desc = symbolic(camlist, 0);
-
-       if (write_regvals(ov, aRegvalsInit518))
-               goto error;
-
-       /* Set LED GPIO pin to output mode */
-       if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
-               goto error;
-
-       /* LED is off by default with OV518; have to explicitly turn it on */
-       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-       else
-               ov51x_led_control(ov, 1);
-
-       /* Don't require compression if dumppix is enabled; otherwise it's
-        * required. OV518 has no uncompressed mode, to save RAM. */
-       if (!dumppix && !ov->compress) {
-               ov->compress = 1;
-               warn("Compression required with OV518...enabling");
-       }
-
-       if (ov->bridge == BRG_OV518) {
-               if (write_regvals(ov, aRegvalsNorm518))
-                       goto error;
-       } else if (ov->bridge == BRG_OV518PLUS) {
-               if (write_regvals(ov, aRegvalsNorm518Plus))
-                       goto error;
-       } else {
-               err("Invalid bridge");
-       }
-
-       if (reg_w(ov, 0x2f, 0x80) < 0)
-               goto error;
-
-       if (ov518_init_compression(ov))
-               goto error;
-
-       if (ov->bridge == BRG_OV518)
-       {
-               struct usb_interface *ifp;
-               struct usb_host_interface *alt;
-               __u16 mxps = 0;
-
-               ifp = usb_ifnum_to_if(ov->dev, 0);
-               if (ifp) {
-                       alt = usb_altnum_to_altsetting(ifp, 7);
-                       if (alt)
-                               mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
-               }
-
-               /* Some OV518s have packet numbering by default, some don't */
-               if (mxps == 897)
-                       ov->packet_numbering = 1;
-               else
-                       ov->packet_numbering = 0;
-       } else {
-               /* OV518+ has packet numbering turned on by default */
-               ov->packet_numbering = 1;
-       }
-
-       ov518_set_packet_size(ov, 0);
-
-       ov->snap_enabled = snapshot;
-
-       /* Test for 76xx */
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               goto error;
-
-       /* The OV518 must be more aggressive about sensor detection since
-        * I2C write will never fail if the sensor is not present. We have
-        * to try to initialize the sensor to detect its presence */
-
-       if (init_ov_sensor(ov) < 0) {
-               /* Test for 6xx0 */
-               ov->primary_i2c_slave = OV6xx0_SID;
-               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-                       goto error;
-
-               if (init_ov_sensor(ov) < 0) {
-                       /* Test for 8xx0 */
-                       ov->primary_i2c_slave = OV8xx0_SID;
-                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-                               goto error;
-
-                       if (init_ov_sensor(ov) < 0) {
-                               err("Can't determine sensor slave IDs");
-                               goto error;
-                       } else {
-                               err("Detected unsupported OV8xx0 sensor");
-                               goto error;
-                       }
-               } else {
-                       if (ov6xx0_configure(ov) < 0) {
-                               err("Failed to configure OV6xx0");
-                               goto error;
-                       }
-               }
-       } else {
-               if (ov7xx0_configure(ov) < 0) {
-                       err("Failed to configure OV7xx0");
-                       goto error;
-               }
-       }
-
-       ov->maxwidth = 352;
-       ov->maxheight = 288;
-
-       // The OV518 cannot go as low as the sensor can
-       ov->minwidth = 160;
-       ov->minheight = 120;
-
-       return 0;
-
-error:
-       err("OV518 Config failed");
-
-       return -EBUSY;
-}
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-
-static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
-{
-       struct video_device *vdev = to_video_device(cd);
-       return video_get_drvdata(vdev);
-}
-
-static ssize_t show_custom_id(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%d\n", ov->customid);
-} 
-static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-
-static ssize_t show_model(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", ov->desc);
-} 
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_bridge(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
-} 
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-
-static ssize_t show_sensor(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
-} 
-static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-
-static ssize_t show_brightness(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_brightness(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_saturation(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_contrast(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_contrast(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_hue(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_hue(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_exposure(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned char exp = 0;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_exposure(ov, &exp);
-       return sprintf(buf, "%d\n", exp >> 8);
-} 
-static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-
-static void ov_create_sysfs(struct video_device *vdev)
-{
-       video_device_create_file(vdev, &class_device_attr_custom_id);
-       video_device_create_file(vdev, &class_device_attr_model);
-       video_device_create_file(vdev, &class_device_attr_bridge);
-       video_device_create_file(vdev, &class_device_attr_sensor);
-       video_device_create_file(vdev, &class_device_attr_brightness);
-       video_device_create_file(vdev, &class_device_attr_saturation);
-       video_device_create_file(vdev, &class_device_attr_contrast);
-       video_device_create_file(vdev, &class_device_attr_hue);
-       video_device_create_file(vdev, &class_device_attr_exposure);
-}
-
-/****************************************************************************
- *  USB routines
- ***************************************************************************/
-
-static int
-ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_interface_descriptor *idesc;
-       struct usb_ov511 *ov;
-       int i;
-
-       PDEBUG(1, "probing for device...");
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       idesc = &intf->cur_altsetting->desc;
-
-       if (idesc->bInterfaceClass != 0xFF)
-               return -ENODEV;
-       if (idesc->bInterfaceSubClass != 0x00)
-               return -ENODEV;
-
-       if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
-               err("couldn't kmalloc ov struct");
-               goto error_out;
-       }
-
-       ov->dev = dev;
-       ov->iface = idesc->bInterfaceNumber;
-       ov->led_policy = led;
-       ov->compress = compress;
-       ov->lightfreq = lightfreq;
-       ov->num_inputs = 1;        /* Video decoder init functs. change this */
-       ov->stop_during_set = !fastset;
-       ov->backlight = backlight;
-       ov->mirror = mirror;
-       ov->auto_brt = autobright;
-       ov->auto_gain = autogain;
-       ov->auto_exp = autoexp;
-
-       switch (le16_to_cpu(dev->descriptor.idProduct)) {
-       case PROD_OV511:
-               ov->bridge = BRG_OV511;
-               ov->bclass = BCL_OV511;
-               break;
-       case PROD_OV511PLUS:
-               ov->bridge = BRG_OV511PLUS;
-               ov->bclass = BCL_OV511;
-               break;
-       case PROD_OV518:
-               ov->bridge = BRG_OV518;
-               ov->bclass = BCL_OV518;
-               break;
-       case PROD_OV518PLUS:
-               ov->bridge = BRG_OV518PLUS;
-               ov->bclass = BCL_OV518;
-               break;
-       case PROD_ME2CAM:
-               if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
-                       goto error;
-               ov->bridge = BRG_OV511PLUS;
-               ov->bclass = BCL_OV511;
-               break;
-       default:
-               err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
-               goto error;
-       }
-
-       info("USB %s video device found", symbolic(brglist, ov->bridge));
-
-       init_waitqueue_head(&ov->wq);
-
-       mutex_init(&ov->lock);  /* to 1 == available */
-       mutex_init(&ov->buf_lock);
-       mutex_init(&ov->i2c_lock);
-       mutex_init(&ov->cbuf_lock);
-
-       ov->buf_state = BUF_NOT_ALLOCATED;
-
-       if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
-               err("usb_make_path error");
-               goto error;
-       }
-
-       /* Allocate control transfer buffer. */
-       /* Must be kmalloc()'ed, for DMA compatibility */
-       ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
-       if (!ov->cbuf)
-               goto error;
-
-       if (ov->bclass == BCL_OV518) {
-               if (ov518_configure(ov) < 0)
-                       goto error;
-       } else {
-               if (ov511_configure(ov) < 0)
-                       goto error;
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].framenum = i;
-               init_waitqueue_head(&ov->frame[i].wq);
-       }
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               ov->sbuf[i].ov = ov;
-               spin_lock_init(&ov->sbuf[i].lock);
-               ov->sbuf[i].n = i;
-       }
-
-       /* Unnecessary? (This is done on open(). Need to make sure variables
-        * are properly initialized without this before removing it, though). */
-       if (ov51x_set_default_params(ov) < 0)
-               goto error;
-
-#ifdef OV511_DEBUG
-       if (dump_bridge) {
-               if (ov->bclass == BCL_OV511)
-                       ov511_dump_regs(ov);
-               else
-                       ov518_dump_regs(ov);
-       }
-#endif
-
-       ov->vdev = video_device_alloc();
-       if (!ov->vdev)
-               goto error;
-
-       memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
-       ov->vdev->dev = &dev->dev;
-       video_set_drvdata(ov->vdev, ov);
-
-       for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
-               /* Minor 0 cannot be specified; assume user wants autodetect */
-               if (unit_video[i] == 0)
-                       break;
-
-               if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
-                       unit_video[i]) >= 0) {
-                       break;
-               }
-       }
-
-       /* Use the next available one */
-       if ((ov->vdev->minor == -1) &&
-           video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
-               err("video_register_device failed");
-               goto error;
-       }
-
-       info("Device at %s registered to minor %d", ov->usb_path,
-            ov->vdev->minor);
-
-       usb_set_intfdata(intf, ov);
-       ov_create_sysfs(ov->vdev);
-       return 0;
-
-error:
-       if (ov->vdev) {
-               if (-1 == ov->vdev->minor)
-                       video_device_release(ov->vdev);
-               else
-                       video_unregister_device(ov->vdev);
-               ov->vdev = NULL;
-       }
-
-       if (ov->cbuf) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-       }
-
-       kfree(ov);
-       ov = NULL;
-
-error_out:
-       err("Camera initialization failed");
-       return -EIO;
-}
-
-static void
-ov51x_disconnect(struct usb_interface *intf)
-{
-       struct usb_ov511 *ov = usb_get_intfdata(intf);
-       int n;
-
-       PDEBUG(3, "");
-
-       usb_set_intfdata (intf, NULL);
-
-       if (!ov)
-               return;
-
-       if (ov->vdev)
-               video_unregister_device(ov->vdev);
-
-       for (n = 0; n < OV511_NUMFRAMES; n++)
-               ov->frame[n].grabstate = FRAME_ERROR;
-
-       ov->curframe = -1;
-
-       /* This will cause the process to request another frame */
-       for (n = 0; n < OV511_NUMFRAMES; n++)
-               wake_up_interruptible(&ov->frame[n].wq);
-
-       wake_up_interruptible(&ov->wq);
-
-       ov->streaming = 0;
-       ov51x_unlink_isoc(ov);
-
-       ov->dev = NULL;
-
-       /* Free the memory */
-       if (ov && !ov->user) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-
-               ov51x_dealloc(ov);
-               kfree(ov);
-               ov = NULL;
-       }
-
-       PDEBUG(3, "Disconnect complete");
-}
-
-static struct usb_driver ov511_driver = {
-       .name =         "ov511",
-       .id_table =     device_table,
-       .probe =        ov51x_probe,
-       .disconnect =   ov51x_disconnect
-};
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init
-usb_ov511_init(void)
-{
-       int retval;
-
-       retval = usb_register(&ov511_driver);
-       if (retval)
-               goto out;
-
-       info(DRIVER_VERSION " : " DRIVER_DESC);
-
-out:
-       return retval;
-}
-
-static void __exit
-usb_ov511_exit(void)
-{
-       usb_deregister(&ov511_driver);
-       info("driver deregistered");
-
-}
-
-module_init(usb_ov511_init);
-module_exit(usb_ov511_exit);
-
diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h
deleted file mode 100644 (file)
index bce9b36..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-#ifndef __LINUX_OV511_H
-#define __LINUX_OV511_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <linux/smp_lock.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#define OV511_DEBUG    /* Turn on debug messages */
-
-#ifdef OV511_DEBUG
-       #define PDEBUG(level, fmt, args...) \
-               if (debug >= (level)) info("[%s:%d] " fmt, \
-               __FUNCTION__, __LINE__ , ## args)
-#else
-       #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { \
-       if ((v) < (mi)) (v) = (mi); \
-       else if ((v) > (ma)) (v) = (ma); \
-}
-
-/* --------------------------------- */
-/* DEFINES FOR OV511 AND OTHER CHIPS */
-/* --------------------------------- */
-
-/* USB IDs */
-#define VEND_OMNIVISION        0x05A9
-#define PROD_OV511     0x0511
-#define PROD_OV511PLUS 0xA511
-#define PROD_OV518     0x0518
-#define PROD_OV518PLUS 0xA518
-
-#define VEND_MATTEL    0x0813
-#define PROD_ME2CAM    0x0002
-
-/* --------------------------------- */
-/*     OV51x REGISTER MNEMONICS      */
-/* --------------------------------- */
-
-/* Camera interface register numbers */
-#define R511_CAM_DELAY         0x10
-#define R511_CAM_EDGE          0x11
-#define R511_CAM_PXCNT         0x12
-#define R511_CAM_LNCNT         0x13
-#define R511_CAM_PXDIV         0x14
-#define R511_CAM_LNDIV         0x15
-#define R511_CAM_UV_EN         0x16
-#define R511_CAM_LINE_MODE     0x17
-#define R511_CAM_OPTS          0x18
-
-/* Snapshot mode camera interface register numbers */
-#define R511_SNAP_FRAME                0x19
-#define R511_SNAP_PXCNT                0x1A
-#define R511_SNAP_LNCNT                0x1B
-#define R511_SNAP_PXDIV                0x1C
-#define R511_SNAP_LNDIV                0x1D
-#define R511_SNAP_UV_EN                0x1E
-#define R511_SNAP_OPTS         0x1F
-
-/* DRAM register numbers */
-#define R511_DRAM_FLOW_CTL     0x20
-#define R511_DRAM_ARCP         0x21
-#define R511_DRAM_MRC          0x22
-#define R511_DRAM_RFC          0x23
-
-/* ISO FIFO register numbers */
-#define R51x_FIFO_PSIZE                0x30    /* 2 bytes wide w/ OV518(+) */
-#define R511_FIFO_OPTS         0x31
-
-/* Parallel IO register numbers */
-#define R511_PIO_OPTS          0x38
-#define R511_PIO_DATA          0x39
-#define R511_PIO_BIST          0x3E
-#define R518_GPIO_IN           0x55    /* OV518(+) only */
-#define R518_GPIO_OUT          0x56    /* OV518(+) only */
-#define R518_GPIO_CTL          0x57    /* OV518(+) only */
-#define R518_GPIO_PULSE_IN     0x58    /* OV518(+) only */
-#define R518_GPIO_PULSE_CLEAR  0x59    /* OV518(+) only */
-#define R518_GPIO_PULSE_POL    0x5a    /* OV518(+) only */
-#define R518_GPIO_PULSE_EN     0x5b    /* OV518(+) only */
-#define R518_GPIO_RESET                0x5c    /* OV518(+) only */
-
-/* I2C registers */
-#define R511_I2C_CTL           0x40
-#define R518_I2C_CTL           0x47    /* OV518(+) only */
-#define R51x_I2C_W_SID         0x41
-#define R51x_I2C_SADDR_3       0x42
-#define R51x_I2C_SADDR_2       0x43
-#define R51x_I2C_R_SID         0x44
-#define R51x_I2C_DATA          0x45
-#define R51x_I2C_CLOCK         0x46
-#define R51x_I2C_TIMEOUT       0x47
-
-/* I2C snapshot registers */
-#define R511_SI2C_SADDR_3      0x48
-#define R511_SI2C_DATA         0x49
-
-/* System control registers */
-#define R51x_SYS_RESET         0x50
-               /* Reset type definitions */
-#define        OV511_RESET_UDC         0x01
-#define        OV511_RESET_I2C         0x02
-#define        OV511_RESET_FIFO        0x04
-#define        OV511_RESET_OMNICE      0x08
-#define        OV511_RESET_DRAM        0x10
-#define        OV511_RESET_CAM_INT     0x20
-#define        OV511_RESET_OV511       0x40
-#define        OV511_RESET_NOREGS      0x3F /* All but OV511 & regs */
-#define        OV511_RESET_ALL         0x7F
-
-#define R511_SYS_CLOCK_DIV     0x51
-#define R51x_SYS_SNAP          0x52
-#define R51x_SYS_INIT          0x53
-#define R511_SYS_PWR_CLK       0x54 /* OV511+/OV518(+) only */
-#define R511_SYS_LED_CTL       0x55 /* OV511+ only */
-#define R511_SYS_USER          0x5E
-#define R511_SYS_CUST_ID       0x5F
-
-/* OmniCE (compression) registers */
-#define R511_COMP_PHY          0x70
-#define R511_COMP_PHUV         0x71
-#define R511_COMP_PVY          0x72
-#define R511_COMP_PVUV         0x73
-#define R511_COMP_QHY          0x74
-#define R511_COMP_QHUV         0x75
-#define R511_COMP_QVY          0x76
-#define R511_COMP_QVUV         0x77
-#define R511_COMP_EN           0x78
-#define R511_COMP_LUT_EN       0x79            
-#define R511_COMP_LUT_BEGIN    0x80
-
-/* --------------------------------- */
-/*         ALTERNATE NUMBERS         */
-/* --------------------------------- */
-
-/* Alternate numbers for various max packet sizes (OV511 only) */
-#define OV511_ALT_SIZE_992     0
-#define OV511_ALT_SIZE_993     1
-#define OV511_ALT_SIZE_768     2
-#define OV511_ALT_SIZE_769     3
-#define OV511_ALT_SIZE_512     4
-#define OV511_ALT_SIZE_513     5
-#define OV511_ALT_SIZE_257     6
-#define OV511_ALT_SIZE_0       7
-
-/* Alternate numbers for various max packet sizes (OV511+ only) */
-#define OV511PLUS_ALT_SIZE_0   0
-#define OV511PLUS_ALT_SIZE_33  1
-#define OV511PLUS_ALT_SIZE_129 2
-#define OV511PLUS_ALT_SIZE_257 3
-#define OV511PLUS_ALT_SIZE_385 4
-#define OV511PLUS_ALT_SIZE_513 5
-#define OV511PLUS_ALT_SIZE_769 6
-#define OV511PLUS_ALT_SIZE_961 7
-
-/* Alternate numbers for various max packet sizes (OV518(+) only) */
-#define OV518_ALT_SIZE_0       0
-#define OV518_ALT_SIZE_128     1
-#define OV518_ALT_SIZE_256     2
-#define OV518_ALT_SIZE_384     3
-#define OV518_ALT_SIZE_512     4
-#define OV518_ALT_SIZE_640     5
-#define OV518_ALT_SIZE_768     6
-#define OV518_ALT_SIZE_896     7
-
-/* --------------------------------- */
-/*     OV7610 REGISTER MNEMONICS     */
-/* --------------------------------- */
-
-/* OV7610 registers */
-#define OV7610_REG_GAIN          0x00  /* gain setting (5:0) */
-#define OV7610_REG_BLUE          0x01  /* blue channel balance */
-#define OV7610_REG_RED           0x02  /* red channel balance */
-#define OV7610_REG_SAT           0x03  /* saturation */
-                                       /* 04 reserved */
-#define OV7610_REG_CNT           0x05  /* Y contrast */
-#define OV7610_REG_BRT           0x06  /* Y brightness */
-                                       /* 08-0b reserved */
-#define OV7610_REG_BLUE_BIAS     0x0C  /* blue channel bias (5:0) */
-#define OV7610_REG_RED_BIAS      0x0D  /* read channel bias (5:0) */
-#define OV7610_REG_GAMMA_COEFF   0x0E  /* gamma settings */
-#define OV7610_REG_WB_RANGE      0x0F  /* AEC/ALC/S-AWB settings */
-#define OV7610_REG_EXP           0x10  /* manual exposure setting */
-#define OV7610_REG_CLOCK         0x11  /* polarity/clock prescaler */
-#define OV7610_REG_COM_A         0x12  /* misc common regs */
-#define OV7610_REG_COM_B         0x13  /* misc common regs */
-#define OV7610_REG_COM_C         0x14  /* misc common regs */
-#define OV7610_REG_COM_D         0x15  /* misc common regs */
-#define OV7610_REG_FIELD_DIVIDE  0x16  /* field interval/mode settings */
-#define OV7610_REG_HWIN_START    0x17  /* horizontal window start */
-#define OV7610_REG_HWIN_END      0x18  /* horizontal window end */
-#define OV7610_REG_VWIN_START    0x19  /* vertical window start */
-#define OV7610_REG_VWIN_END      0x1A  /* vertical window end */
-#define OV7610_REG_PIXEL_SHIFT   0x1B  /* pixel shift */
-#define OV7610_REG_ID_HIGH       0x1C  /* manufacturer ID MSB */
-#define OV7610_REG_ID_LOW        0x1D  /* manufacturer ID LSB */
-                                       /* 0e-0f reserved */
-#define OV7610_REG_COM_E         0x20  /* misc common regs */
-#define OV7610_REG_YOFFSET       0x21  /* Y channel offset */
-#define OV7610_REG_UOFFSET       0x22  /* U channel offset */
-                                       /* 23 reserved */
-#define OV7610_REG_ECW           0x24  /* Exposure white level for AEC */
-#define OV7610_REG_ECB           0x25  /* Exposure black level for AEC */
-#define OV7610_REG_COM_F         0x26  /* misc settings */
-#define OV7610_REG_COM_G         0x27  /* misc settings */
-#define OV7610_REG_COM_H         0x28  /* misc settings */
-#define OV7610_REG_COM_I         0x29  /* misc settings */
-#define OV7610_REG_FRAMERATE_H   0x2A  /* frame rate MSB + misc */
-#define OV7610_REG_FRAMERATE_L   0x2B  /* frame rate LSB */
-#define OV7610_REG_ALC           0x2C  /* Auto Level Control settings */
-#define OV7610_REG_COM_J         0x2D  /* misc settings */
-#define OV7610_REG_VOFFSET       0x2E  /* V channel offset adjustment */
-#define OV7610_REG_ARRAY_BIAS   0x2F   /* Array bias -- don't change */
-                                       /* 30-32 reserved */
-#define OV7610_REG_YGAMMA        0x33  /* misc gamma settings (7:6) */
-#define OV7610_REG_BIAS_ADJUST   0x34  /* misc bias settings */
-#define OV7610_REG_COM_L         0x35  /* misc settings */
-                                       /* 36-37 reserved */
-#define OV7610_REG_COM_K         0x38  /* misc registers */
-
-/* --------------------------------- */
-/*           I2C ADDRESSES           */
-/* --------------------------------- */
-
-#define OV7xx0_SID   0x42
-#define OV6xx0_SID   0xC0
-#define OV8xx0_SID   0xA0
-#define KS0127_SID   0xD8
-#define SAA7111A_SID 0x48
-
-/* --------------------------------- */
-/*       MISCELLANEOUS DEFINES       */
-/* --------------------------------- */
-
-#define I2C_CLOCK_PRESCALER    0x03
-
-#define FRAMES_PER_DESC                10      /* FIXME - What should this be? */
-#define MAX_FRAME_SIZE_PER_DESC        993     /* For statically allocated stuff */
-#define PIXELS_PER_SEG         256     /* Pixels per segment */
-
-#define OV511_ENDPOINT_ADDRESS 1       /* Isoc endpoint number */
-
-#define OV511_NUMFRAMES        2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-       #error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF          2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE                4
-
-/* Size of usb_make_path() buffer */
-#define OV511_USB_PATH_LEN     64
-
-/* Bridge types */
-enum {
-       BRG_UNKNOWN,
-       BRG_OV511,
-       BRG_OV511PLUS,
-       BRG_OV518,
-       BRG_OV518PLUS,
-};
-
-/* Bridge classes */
-enum {
-       BCL_UNKNOWN,
-       BCL_OV511,
-       BCL_OV518,
-};
-
-/* Sensor types */
-enum {
-       SEN_UNKNOWN,
-       SEN_OV76BE,
-       SEN_OV7610,
-       SEN_OV7620,
-       SEN_OV7620AE,
-       SEN_OV6620,
-       SEN_OV6630,
-       SEN_OV6630AE,
-       SEN_OV6630AF,
-       SEN_OV8600,
-       SEN_KS0127,
-       SEN_KS0127B,
-       SEN_SAA7111A,
-};
-
-enum {
-       STATE_SCANNING,         /* Scanning for start */
-       STATE_HEADER,           /* Parsing header */
-       STATE_LINES,            /* Parsing lines */
-};
-
-/* Buffer states */
-enum {
-       BUF_NOT_ALLOCATED,
-       BUF_ALLOCATED,
-};
-
-/* --------- Definition of ioctl interface --------- */
-
-#define OV511_INTERFACE_VER 101
-
-/* LED options */
-enum {
-       LED_OFF,
-       LED_ON,
-       LED_AUTO,
-};
-
-/* Raw frame formats */
-enum {
-       RAWFMT_INVALID,
-       RAWFMT_YUV400,
-       RAWFMT_YUV420,
-       RAWFMT_YUV422,
-       RAWFMT_GBR422,
-};
-
-struct ov511_i2c_struct {
-       unsigned char slave; /* Write slave ID (read ID - 1) */
-       unsigned char reg;   /* Index of register */
-       unsigned char value; /* User sets this w/ write, driver does w/ read */
-       unsigned char mask;  /* Bits to be changed. Not used with read ops */
-};
-
-/* ioctls */
-#define OV511IOC_WI2C     _IOW('v', BASE_VIDIOCPRIVATE + 5, \
-                              struct ov511_i2c_struct)
-#define OV511IOC_RI2C    _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
-                              struct ov511_i2c_struct)
-/* ------------- End IOCTL interface -------------- */
-
-struct usb_ov511;              /* Forward declaration */
-
-struct ov511_sbuf {
-       struct usb_ov511 *ov;
-       unsigned char *data;
-       struct urb *urb;
-       spinlock_t lock;
-       int n;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-struct ov511_regvals {
-       enum {
-               OV511_DONE_BUS,
-               OV511_REG_BUS,
-               OV511_I2C_BUS,
-       } bus;
-       unsigned char reg;
-       unsigned char val;
-};
-
-struct ov511_frame {
-       int framenum;           /* Index of this frame */
-       unsigned char *data;    /* Frame buffer */
-       unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
-       unsigned char *rawdata; /* Raw camera data buffer */
-       unsigned char *compbuf; /* Temp buffer for decompressor */
-
-       int depth;              /* Bytes per pixel */
-       int width;              /* Width application is expecting */
-       int height;             /* Height application is expecting */
-
-       int rawwidth;           /* Actual width of frame sent from camera */
-       int rawheight;          /* Actual height of frame sent from camera */
-
-       int sub_flag;           /* Sub-capture mode for this frame? */
-       unsigned int format;    /* Format for this frame */
-       int compressed;         /* Is frame compressed? */
-
-       volatile int grabstate; /* State of grabbing */
-       int scanstate;          /* State of scanning */
-
-       int bytes_recvd;        /* Number of image bytes received from camera */
-
-       long bytes_read;        /* Amount that has been read() */
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int snapshot;           /* True if frame was a snapshot */
-};
-
-#define DECOMP_INTERFACE_VER 4
-
-/* Compression module operations */
-struct ov51x_decomp_ops {
-       int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       struct module *owner;
-};
-
-struct usb_ov511 {
-       struct video_device *vdev;
-       struct usb_device *dev;
-
-       int customid;
-       char *desc;
-       unsigned char iface;
-       char usb_path[OV511_USB_PATH_LEN];
-
-       /* Determined by sensor type */
-       int maxwidth;
-       int maxheight;
-       int minwidth;
-       int minheight;
-
-       int brightness;
-       int colour;
-       int contrast;
-       int hue;
-       int whiteness;
-       int exposure;
-       int auto_brt;           /* Auto brightness enabled flag */
-       int auto_gain;          /* Auto gain control enabled flag */
-       int auto_exp;           /* Auto exposure enabled flag */
-       int backlight;          /* Backlight exposure algorithm flag */
-       int mirror;             /* Image is reversed horizontally */
-
-       int led_policy;         /* LED: off|on|auto; OV511+ only */
-
-       struct mutex lock;      /* Serializes user-accessible operations */
-       int user;               /* user count for exclusive use */
-
-       int streaming;          /* Are we streaming Isochronous? */
-       int grabbing;           /* Are we grabbing? */
-
-       int compress;           /* Should the next frame be compressed? */
-       int compress_inited;    /* Are compression params uploaded? */
-
-       int lightfreq;          /* Power (lighting) frequency */
-       int bandfilt;           /* Banding filter enabled flag */
-
-       unsigned char *fbuf;    /* Videodev buffer area */
-       unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
-       unsigned char *rawfbuf; /* Raw camera data buffer area */
-
-       int sub_flag;           /* Pix Array subcapture on flag */
-       int subx;               /* Pix Array subcapture x offset */
-       int suby;               /* Pix Array subcapture y offset */
-       int subw;               /* Pix Array subcapture width */
-       int subh;               /* Pix Array subcapture height */
-
-       int curframe;           /* Current receiving sbuf */
-       struct ov511_frame frame[OV511_NUMFRAMES];      
-
-       struct ov511_sbuf sbuf[OV511_NUMSBUF];
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int snap_enabled;       /* Snapshot mode enabled */
-       
-       int bridge;             /* Type of bridge (BRG_*) */
-       int bclass;             /* Class of bridge (BCL_*) */
-       int sensor;             /* Type of image sensor chip (SEN_*) */
-
-       int packet_size;        /* Frame size per isoc desc */
-       int packet_numbering;   /* Is ISO frame numbering enabled? */
-
-       /* Framebuffer/sbuf management */
-       int buf_state;
-       struct mutex buf_lock;
-
-       struct ov51x_decomp_ops *decomp_ops;
-
-       /* Stop streaming while changing picture settings */
-       int stop_during_set;
-
-       int stopped;            /* Streaming is temporarily paused */
-
-       /* Video decoder stuff */
-       int input;              /* Composite, S-VIDEO, etc... */
-       int num_inputs;         /* Number of inputs */
-       int norm;               /* NTSC / PAL / SECAM */
-       int has_decoder;        /* Device has a video decoder */
-       int pal;                /* Device is designed for PAL resolution */
-
-       /* I2C interface */
-       struct mutex i2c_lock;    /* Protect I2C controller regs */
-       unsigned char primary_i2c_slave;  /* I2C write id of sensor */
-
-       /* Control transaction stuff */
-       unsigned char *cbuf;            /* Buffer for payload */
-       struct mutex cbuf_lock;
-};
-
-/* Used to represent a list of values and their respective symbolic names */
-struct symbolic_list {
-       int num;
-       char *name;
-};
-
-#define NOT_DEFINED_STR "Unknown"
-
-/* Returns the name of the matching element in the symbolic_list array. The
- * end of the list must be marked with an element that has a NULL name.
- */
-static inline char * 
-symbolic(struct symbolic_list list[], int num)
-{
-       int i;
-
-       for (i = 0; list[i].name != NULL; i++)
-                       if (list[i].num == num)
-                               return (list[i].name);
-
-       return (NOT_DEFINED_STR);
-}
-
-/* Compression stuff */
-
-#define OV511_QUANTABLESIZE    64
-#define OV518_QUANTABLESIZE    32
-
-#define OV511_YQUANTABLE { \
-       0, 1, 1, 2, 2, 3, 3, 4, \
-       1, 1, 1, 2, 2, 3, 4, 4, \
-       1, 1, 2, 2, 3, 4, 4, 4, \
-       2, 2, 2, 3, 4, 4, 4, 4, \
-       2, 2, 3, 4, 4, 5, 5, 5, \
-       3, 3, 4, 4, 5, 5, 5, 5, \
-       3, 4, 4, 4, 5, 5, 5, 5, \
-       4, 4, 4, 4, 5, 5, 5, 5  \
-}
-
-#define OV511_UVQUANTABLE { \
-       0, 2, 2, 3, 4, 4, 4, 4, \
-       2, 2, 2, 4, 4, 4, 4, 4, \
-       2, 2, 3, 4, 4, 4, 4, 4, \
-       3, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4  \
-}
-
-#define OV518_YQUANTABLE { \
-       5, 4, 5, 6, 6, 7, 7, 7, \
-       5, 5, 5, 5, 6, 7, 7, 7, \
-       6, 6, 6, 6, 7, 7, 7, 8, \
-       7, 7, 6, 7, 7, 7, 8, 8  \
-}
-
-#define OV518_UVQUANTABLE { \
-       6, 6, 6, 7, 7, 7, 7, 7, \
-       6, 6, 6, 7, 7, 7, 7, 7, \
-       6, 6, 6, 7, 7, 7, 7, 8, \
-       7, 7, 7, 7, 7, 7, 8, 8  \
-}
-
-#endif
diff --git a/drivers/usb/media/pwc/Makefile b/drivers/usb/media/pwc/Makefile
deleted file mode 100644 (file)
index 2d93a77..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-ifneq ($(KERNELRELEASE),)
-
-pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
-
-obj-$(CONFIG_USB_PWC) += pwc.o
-
-else
-
-KDIR := /lib/modules/$(shell uname -r)/build
-PWD := $(shell pwd)
-
-default:
-       $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
-
-endif
-
-clean:
-       rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c 
-       rm -rf .tmp_versions
-
diff --git a/drivers/usb/media/pwc/philips.txt b/drivers/usb/media/pwc/philips.txt
deleted file mode 100644 (file)
index 04a640d..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-This file contains some additional information for the Philips and OEM webcams.
-E-mail: webcam@smcc.demon.nl                        Last updated: 2004-01-19
-Site: http://www.smcc.demon.nl/webcam/
-
-As of this moment, the following cameras are supported:
- * Philips PCA645
- * Philips PCA646
- * Philips PCVC675
- * Philips PCVC680
- * Philips PCVC690
- * Philips PCVC720/40
- * Philips PCVC730
- * Philips PCVC740
- * Philips PCVC750
- * Askey VC010
- * Creative Labs Webcam 5
- * Creative Labs Webcam Pro Ex
- * Logitech QuickCam 3000 Pro
- * Logitech QuickCam 4000 Pro
- * Logitech QuickCam Notebook Pro
- * Logitech QuickCam Zoom
- * Logitech QuickCam Orbit
- * Logitech QuickCam Sphere
- * Samsung MPC-C10
- * Samsung MPC-C30
- * Sotec Afina Eye
- * AME CU-001
- * Visionite VCS-UM100
- * Visionite VCS-UC300
-
-The main webpage for the Philips driver is at the address above. It contains
-a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
-contains decompression routines that allow you to use higher image sizes and
-framerates; in addition the webcam uses less bandwidth on the USB bus (handy
-if you want to run more than 1 camera simultaneously). These routines fall
-under a NDA, and may therefor not be distributed as source; however, its use
-is completely optional.
-
-You can build this code either into your kernel, or as a module. I recommend
-the latter, since it makes troubleshooting a lot easier. The built-in
-microphone is supported through the USB Audio class.
-
-When you load the module you can set some default settings for the
-camera; some programs depend on a particular image-size or -format and
-don't know how to set it properly in the driver. The options are:
-
-size
-   Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
-   'vga', for an image size of resp. 128x96, 160x120, 176x144,
-   320x240, 352x288 and 640x480 (of course, only for those cameras that 
-   support these resolutions).
-
-fps
-   Specifies the desired framerate. Is an integer in the range of 4-30.
-
-fbufs
-   This paramter specifies the number of internal buffers to use for storing 
-   frames from the cam. This will help if the process that reads images from 
-   the cam is a bit slow or momentarely busy. However, on slow machines it 
-   only introduces lag, so choose carefully. The default is 3, which is 
-   reasonable. You can set it between 2 and 5.
-
-mbufs
-   This is an integer between 1 and 10. It will tell the module the number of
-   buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends.
-   The default is 2, which is adequate for most applications (double
-   buffering).
-      
-   Should you experience a lot of 'Dumping frame...' messages during
-   grabbing with a tool that uses mmap(), you might want to increase if. 
-   However, it doesn't really buffer images, it just gives you a bit more
-   slack when your program is behind. But you need a multi-threaded or
-   forked program to really take advantage of these buffers.
-
-   The absolute maximum is 10, but don't set it too high!  Every buffer takes
-   up 460 KB of RAM, so unless you have a lot of memory setting this to
-   something more than 4 is an absolute waste.  This memory is only
-   allocated during open(), so nothing is wasted when the camera is not in
-   use.
-
-power_save
-   When power_save is enabled (set to 1), the module will try to shut down
-   the cam on close() and re-activate on open(). This will save power and
-   turn off the LED. Not all cameras support this though (the 645 and 646
-   don't have power saving at all), and some models don't work either (they
-   will shut down, but never wake up). Consider this experimental. By
-   default this option is disabled.
-
-compression (only useful with the plugin)
-   With this option you can control the compression factor that the camera
-   uses to squeeze the image through the USB bus. You can set the 
-   parameter between 0 and 3:
-     0 = prefer uncompressed images; if the requested mode is not available
-         in an uncompressed format, the driver will silently switch to low
-         compression.
-     1 = low compression.
-     2 = medium compression.
-     3 = high compression.
-      
-   High compression takes less bandwidth of course, but it could also
-   introduce some unwanted artefacts. The default is 2, medium compression.
-   See the FAQ on the website for an overview of which modes require
-   compression.
-
-   The compression parameter does not apply to the 645 and 646 cameras
-   and OEM models derived from those (only a few). Most cams honour this
-   parameter.
-
-leds
-   This settings takes 2 integers, that define the on/off time for the LED
-   (in milliseconds). One of the interesting things that you can do with
-   this is let the LED blink while the camera is in use. This:
-
-     leds=500,500
-      
-   will blink the LED once every second. But with:
-
-     leds=0,0
-
-   the LED never goes on, making it suitable for silent surveillance.
-
-   By default the camera's LED is on solid while in use, and turned off
-   when the camera is not used anymore.
-
-   This parameter works only with the ToUCam range of cameras (720, 730, 740,
-   750) and OEMs. For other cameras this command is silently ignored, and 
-   the LED cannot be controlled.
-
-   Finally: this parameters does not take effect UNTIL the first time you
-   open the camera device. Until then, the LED remains on.
-
-dev_hint
-   A long standing problem with USB devices is their dynamic nature: you
-   never know what device a camera gets assigned; it depends on module load
-   order, the hub configuration, the order in which devices are plugged in,
-   and the phase of the moon (i.e. it can be random). With this option you
-   can give the driver a hint as to what video device node (/dev/videoX) it
-   should use with a specific camera. This is also handy if you have two
-   cameras of the same model.
-
-   A camera is specified by its type (the number from the camera model,
-   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
-   in /proc/bus/usb/devices). A hint consists of a string with the following
-   format:
-
-      [type[.serialnumber]:]node
-      
-   The square brackets mean that both the type and the serialnumber are
-   optional, but a serialnumber cannot be specified without a type (which
-   would be rather pointless). The serialnumber is separated from the type
-   by a '.'; the node number by a ':'.
-   
-   This somewhat cryptic syntax is best explained by a few examples:
-
-     dev_hint=3,5              The first detected cam gets assigned
-                               /dev/video3, the second /dev/video5. Any
-                               other cameras will get the first free 
-                               available slot (see below).
-
-     dev_hint=645:1,680:2      The PCA645 camera will get /dev/video1,
-                               and a PCVC680 /dev/video2.
-                               
-     dev_hint=645.0123:3,645.4567:0    The PCA645 camera with serialnumber 
-                                        0123 goes to /dev/video3, the same
-                                        camera model with the 4567 serial
-                                        gets /dev/video0.
-
-     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the 
-                                next 3 Philips cams will use /dev/video4 
-                                through /dev/video6.
-
-   Some points worth knowing:
-   - Serialnumbers are case sensitive and must be written full, including 
-     leading zeroes (it's treated as a string).
-   - If a device node is already occupied, registration will fail and 
-     the webcam is not available.
-   - You can have up to 64 video devices; be sure to make enough device
-     nodes in /dev if you want to spread the numbers (this does not apply
-     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
-   - If a camera does not match any dev_hint, it will simply get assigned
-     the first available device node, just as it used to be.
-
-trace
-   In order to better detect problems, it is now possible to turn on a
-   'trace' of some of the calls the module makes; it logs all items in your
-   kernel log at debug level.
-
-   The trace variable is a bitmask; each bit represents a certain feature.
-   If you want to trace something, look up the bit value(s) in the table 
-   below, add the values together and supply that to the trace variable.
-
-   Value  Value   Description                                     Default
-   (dec)  (hex)
-       1    0x1   Module initialization; this will log messages       On
-                  while loading and unloading the module
-
-       2    0x2   probe() and disconnect() traces                     On
-
-       4    0x4   Trace open() and close() calls                      Off
-
-       8    0x8   read(), mmap() and associated ioctl() calls         Off
-
-      16   0x10   Memory allocation of buffers, etc.                  Off
-
-      32   0x20   Showing underflow, overflow and Dumping frame       On
-                  messages
-
-      64   0x40   Show viewport and image sizes                       Off
-
-     128   0x80   PWCX debugging                                      Off
-
-   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
-   so you would supply trace=12 during insmod or modprobe. If
-   you want to turn the initialization and probing tracing off, set trace=0.
-   The default value for trace is 35 (0x23).
-
-
-
-Example:
-     
-     # modprobe pwc size=cif fps=15 power_save=1
-
-The fbufs, mbufs and trace parameters are global and apply to all connected
-cameras. Each camera has its own set of buffers.
-
-size and fps only specify defaults when you open() the device; this is to
-accommodate some tools that don't set the size. You can change these
-settings after open() with the Video4Linux ioctl() calls. The default of
-defaults is QCIF size at 10 fps.
-
-The compression parameter is semiglobal; it sets the initial compression
-preference for all camera's, but this parameter can be set per camera with
-the VIDIOCPWCSCQUAL ioctl() call.
-
-All parameters are optional.
-
diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c
deleted file mode 100644 (file)
index 0398b81..0000000
+++ /dev/null
@@ -1,1541 +0,0 @@
-/* Driver for Philips webcam
-   Functions that send various control messages to the webcam, including
-   video modes.
-   (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added methods for changing white balance and 
-                          red/green gains
- */
-
-/* Control functions for the cam; brightness, contrast, video mode, etc. */
-
-#ifdef __KERNEL__
-#include <asm/uaccess.h> 
-#endif
-#include <asm/errno.h>
-#include "pwc.h"
-#include "pwc-ioctl.h"
-#include "pwc-uncompress.h"
-#include "pwc-kiara.h"
-#include "pwc-timon.h"
-
-/* Request types: video */
-#define SET_LUM_CTL                    0x01
-#define GET_LUM_CTL                    0x02
-#define SET_CHROM_CTL                  0x03
-#define GET_CHROM_CTL                  0x04
-#define SET_STATUS_CTL                 0x05
-#define GET_STATUS_CTL                 0x06
-#define SET_EP_STREAM_CTL              0x07
-#define GET_EP_STREAM_CTL              0x08
-#define SET_MPT_CTL                    0x0D
-#define GET_MPT_CTL                    0x0E
-
-/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
-#define AGC_MODE_FORMATTER                     0x2000
-#define PRESET_AGC_FORMATTER                   0x2100
-#define SHUTTER_MODE_FORMATTER                 0x2200
-#define PRESET_SHUTTER_FORMATTER               0x2300
-#define PRESET_CONTOUR_FORMATTER               0x2400
-#define AUTO_CONTOUR_FORMATTER                 0x2500
-#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
-#define CONTRAST_FORMATTER                     0x2700
-#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
-#define FLICKERLESS_MODE_FORMATTER             0x2900
-#define AE_CONTROL_SPEED                       0x2A00
-#define BRIGHTNESS_FORMATTER                   0x2B00
-#define GAMMA_FORMATTER                                0x2C00
-
-/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
-#define WB_MODE_FORMATTER                      0x1000
-#define AWB_CONTROL_SPEED_FORMATTER            0x1100
-#define AWB_CONTROL_DELAY_FORMATTER            0x1200
-#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
-#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
-#define COLOUR_MODE_FORMATTER                  0x1500
-#define SATURATION_MODE_FORMATTER1             0x1600
-#define SATURATION_MODE_FORMATTER2             0x1700
-
-/* Selectors for the Status controls [GS]ET_STATUS_CTL */
-#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
-#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
-#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
-#define READ_AGC_FORMATTER                     0x0500
-#define READ_SHUTTER_FORMATTER                 0x0600
-#define READ_RED_GAIN_FORMATTER                        0x0700
-#define READ_BLUE_GAIN_FORMATTER               0x0800
-#define SENSOR_TYPE_FORMATTER1                 0x0C00
-#define READ_RAW_Y_MEAN_FORMATTER              0x3100
-#define SET_POWER_SAVE_MODE_FORMATTER          0x3200
-#define MIRROR_IMAGE_FORMATTER                 0x3300
-#define LED_FORMATTER                          0x3400
-#define SENSOR_TYPE_FORMATTER2                 0x3700
-
-/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
-#define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
-
-/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
-#define PT_RELATIVE_CONTROL_FORMATTER          0x01
-#define PT_RESET_CONTROL_FORMATTER             0x02
-#define PT_STATUS_FORMATTER                    0x03
-
-static const char *size2name[PSZ_MAX] =
-{
-       "subQCIF",
-       "QSIF",
-       "QCIF",
-       "SIF",
-       "CIF",
-       "VGA",
-};  
-
-/********/
-
-/* Entries for the Nala (645/646) camera; the Nala doesn't have compression 
-   preferences, so you either get compressed or non-compressed streams.
-   
-   An alternate value of 0 means this mode is not available at all.
- */
-
-struct Nala_table_entry {
-       char alternate;                 /* USB alternate setting */
-       int compressed;                 /* Compressed yes/no */
-
-       unsigned char mode[3];          /* precomputed mode table */
-};
-
-static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
-{
-#include "pwc-nala.h"
-};
-
-
-/****************************************************************************/
-
-
-#define SendControlMsg(request, value, buflen) \
-       usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
-               request, \
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
-               value, \
-               pdev->vcinterface, \
-               &buf, buflen, 500)
-
-#define RecvControlMsg(request, value, buflen) \
-       usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
-               request, \
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
-               value, \
-               pdev->vcinterface, \
-               &buf, buflen, 500)
-
-
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
-       int i;
-       unsigned char *s;
-       char buf[100], *d;
-
-       s = (unsigned char *)p;
-       d = buf;
-       *d = '\0';
-       Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
-       for (i = 0; i < len; i++) {
-               d += sprintf(d, "%02X ", *s++);
-               if ((i & 0xF) == 0xF) {
-                       Debug("%s\n", buf);
-                       d = buf;
-                       *d = '\0';
-               }
-       }
-       if ((i & 0xF) != 0)
-               Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
-{
-       return usb_control_msg(udev,
-               usb_sndctrlpipe(udev, 0),
-               SET_EP_STREAM_CTL,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               VIDEO_OUTPUT_CONTROL_FORMATTER,
-               index,
-               buf, buflen, 1000);
-}
-
-
-
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
-{
-       unsigned char buf[3];
-       int ret, fps;
-       struct Nala_table_entry *pEntry;
-       int frames2frames[31] =
-       { /* closest match of framerate */
-          0,  0,  0,  0,  4,  /*  0-4  */
-          5,  5,  7,  7, 10,  /*  5-9  */
-          10, 10, 12, 12, 15,  /* 10-14 */
-          15, 15, 15, 20, 20,  /* 15-19 */
-          20, 20, 20, 24, 24,  /* 20-24 */
-          24, 24, 24, 24, 24,  /* 25-29 */
-          24                   /* 30    */
-       };
-       int frames2table[31] = 
-       { 0, 0, 0, 0, 0, /*  0-4  */
-         1, 1, 1, 2, 2, /*  5-9  */
-         3, 3, 4, 4, 4, /* 10-14 */
-         5, 5, 5, 5, 5, /* 15-19 */
-         6, 6, 6, 6, 7, /* 20-24 */
-         7, 7, 7, 7, 7, /* 25-29 */
-         7              /* 30    */
-       };
-       
-       if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
-               return -EINVAL;
-       frames = frames2frames[frames];
-       fps = frames2table[frames];
-       pEntry = &Nala_table[size][fps];
-       if (pEntry->alternate == 0)
-               return -EINVAL;
-
-       if (pEntry->compressed)
-               return -ENOENT; /* Not supported. */
-
-       memcpy(buf, pEntry->mode, 3);   
-       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
-       if (ret < 0) {
-               Debug("Failed to send video command... %d\n", ret);
-               return ret;
-       }
-       if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
-        {
-          switch(pdev->type) {
-            case 645:
-            case 646:
-/*            pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-              break;
-
-            case 675:
-            case 680:
-            case 690:
-            case 720:
-            case 730:
-            case 740:
-            case 750:
-/*            pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-              break;
-          }
-       }
-       pdev->cmd_len = 3;
-       memcpy(pdev->cmd_buf, buf, 3);
-
-       /* Set various parameters */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->valternate = pEntry->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
-       if (pEntry->compressed) {
-               if (pdev->release < 5) { /* 4 fold compression */
-                       pdev->vbandlength = 528;
-                       pdev->frame_size /= 4;
-               }
-               else {
-                       pdev->vbandlength = 704;
-                       pdev->frame_size /= 3;
-               }
-       }
-       else
-               pdev->vbandlength = 0;
-       return 0;
-}
-
-
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
-{
-       unsigned char buf[13];
-       const struct Timon_table_entry *pChoose;
-       int ret, fps;
-
-       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
-               return -EINVAL;
-       if (size == PSZ_VGA && frames > 15)
-               return -EINVAL;
-       fps = (frames / 5) - 1;
-
-       /* Find a supported framerate with progressively higher compression ratios
-          if the preferred ratio is not available.
-       */
-       pChoose = NULL;
-       while (compression <= 3) {
-          pChoose = &Timon_table[size][fps][compression];
-          if (pChoose->alternate != 0)
-            break;
-          compression++;
-       }
-       if (pChoose == NULL || pChoose->alternate == 0)
-               return -ENOENT; /* Not supported. */
-
-       memcpy(buf, pChoose->mode, 13);
-       if (snapshot)
-               buf[0] |= 0x80;
-       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
-       if (ret < 0)
-               return ret;
-
-/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-          pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-
-       pdev->cmd_len = 13;
-       memcpy(pdev->cmd_buf, buf, 13);
-
-       /* Set various parameters */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->vsnapshot = snapshot;
-       pdev->valternate = pChoose->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->vbandlength = pChoose->bandlength;
-       if (pChoose->bandlength > 0)
-               pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
-       else
-               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
-       return 0;
-}
-
-
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
-{
-       const struct Kiara_table_entry *pChoose = NULL;
-       int fps, ret;
-       unsigned char buf[12];
-       struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
-
-       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
-               return -EINVAL;
-       if (size == PSZ_VGA && frames > 15)
-               return -EINVAL;
-       fps = (frames / 5) - 1;
-
-       /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-       if (size == PSZ_VGA && frames == 5 && snapshot)
-       {
-               /* Only available in case the raw palette is selected or 
-                  we have the decompressor available. This mode is 
-                  only available in compressed form 
-               */
-               if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               {
-                       Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
-                       pChoose = &RawEntry;
-               }
-               else
-               {
-                       Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
-               }
-       }
-       else
-       {
-               /* Find a supported framerate with progressively higher compression ratios
-                  if the preferred ratio is not available.
-                   Skip this step when using RAW modes.
-               */
-               while (compression <= 3) {
-                       pChoose = &Kiara_table[size][fps][compression];
-                       if (pChoose->alternate != 0)
-                               break;
-                       compression++;
-               }
-       }
-       if (pChoose == NULL || pChoose->alternate == 0)
-               return -ENOENT; /* Not supported. */
-
-       Debug("Using alternate setting %d.\n", pChoose->alternate);
-       
-       /* usb_control_msg won't take staticly allocated arrays as argument?? */
-       memcpy(buf, pChoose->mode, 12);
-       if (snapshot)
-               buf[0] |= 0x80;
-
-       /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
-       ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
-       if (ret < 0)
-               return ret;
-
-/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-         pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-
-       pdev->cmd_len = 12;
-       memcpy(pdev->cmd_buf, buf, 12);
-       /* All set and go */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->vsnapshot = snapshot;
-       pdev->valternate = pChoose->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->vbandlength = pChoose->bandlength;
-       if (pdev->vbandlength > 0)
-               pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
-       else
-               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
-       return 0;
-}
-
-
-
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
-       int i, factor = 0, filler = 0;
-
-       /* for PALETTE_YUV420P */
-       switch(pdev->vpalette)
-       {
-       case VIDEO_PALETTE_YUV420P:
-               factor = 6;
-               filler = 128;
-               break;
-       case VIDEO_PALETTE_RAW:
-               factor = 6; /* can be uncompressed YUV420P */
-               filler = 0;
-               break;
-       }
-
-       /* Set sizes in bytes */
-       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
-       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
-
-       /* Align offset, or you'll get some very weird results in
-          YUV420 mode... x must be multiple of 4 (to get the Y's in
-          place), and y even (or you'll mixup U & V). This is less of a
-          problem for YUV420P.
-        */
-       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
-       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
-       /* Fill buffers with gray or black */
-       for (i = 0; i < MAX_IMAGES; i++) {
-               if (pdev->image_ptr[i] != NULL)
-                       memset(pdev->image_ptr[i], filler, pdev->view.size);
-       }
-}
-
-
-
-/**
-   @pdev: device structure
-   @width: viewport width
-   @height: viewport height
-   @frame: framerate, in fps
-   @compression: preferred compression ratio
-   @snapshot: snapshot mode or streaming
- */
-int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
-{
-        int ret, size;
-
-        Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
-       size = pwc_decode_size(pdev, width, height);
-       if (size < 0) {
-               Debug("Could not find suitable size.\n");
-               return -ERANGE;
-       }
-       Debug("decode_size = %d.\n", size);
-
-        ret = -EINVAL;
-       switch(pdev->type) {
-       case 645:
-       case 646:
-               ret = set_video_mode_Nala(pdev, size, frames);
-               break;
-
-       case 675:
-       case 680:
-       case 690:
-               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
-               break;
-       
-       case 720:
-       case 730:
-       case 740:
-       case 750:
-               ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-               break;
-       }
-       if (ret < 0) {
-               if (ret == -ENOENT)
-                       Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
-               else {
-                       Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-               }
-               return ret;
-       }
-       pdev->view.x = width;
-       pdev->view.y = height;
-       pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
-       pwc_set_image_buffer_size(pdev);
-       Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
-       return 0;
-}
-
-
-/* BRIGHTNESS */
-
-int pwc_get_brightness(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-
-       ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);     
-       if (ret < 0)
-               return ret;
-       return buf << 9;
-}
-
-int pwc_set_brightness(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 9) & 0x7f;
-       return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
-}
-
-/* CONTRAST */
-
-int pwc_get_contrast(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-
-       ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       return buf << 10;
-}
-
-int pwc_set_contrast(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 10) & 0x3f;
-       return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1);
-}
-
-/* GAMMA */
-
-int pwc_get_gamma(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       return buf << 11;
-}
-
-int pwc_set_gamma(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 11) & 0x1f;
-       return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1);
-}
-
-
-/* SATURATION */
-
-int pwc_get_saturation(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-
-       if (pdev->type < 675)
-               return -1;
-       ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
-       if (ret < 0)
-               return ret;
-       return 32768 + buf * 327;
-}
-
-int pwc_set_saturation(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (pdev->type < 675)
-               return -EINVAL;
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* saturation ranges from -100 to +100 */
-       buf = (value - 32768) / 327;
-       return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
-}
-
-/* AGC */
-
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
-{
-       char buf;
-       int ret;
-       
-       if (mode)
-               buf = 0x0; /* auto */
-       else
-               buf = 0xff; /* fixed */
-
-       ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1);
-       
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-               buf = (value >> 10) & 0x3F;
-               ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
-       }
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-
-       if (buf != 0) { /* fixed */
-               ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
-               if (ret < 0)
-                       return ret;
-               if (buf > 0x3F)
-                       buf = 0x3F;
-               *value = (buf << 10);           
-       }
-       else { /* auto */
-               ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1);
-               if (ret < 0)
-                       return ret;
-               /* Gah... this value ranges from 0x00 ... 0x9F */
-               if (buf > 0x9F)
-                       buf = 0x9F;
-               *value = -(48 + buf * 409);
-       }
-
-       return 0;
-}
-
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
-{
-       char buf[2];
-       int speed, ret;
-
-
-       if (mode)
-               buf[0] = 0x0;   /* auto */
-       else
-               buf[0] = 0xff; /* fixed */
-       
-       ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1);
-
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-               switch(pdev->type) {
-               case 675:
-               case 680:
-               case 690:
-                       /* speed ranges from 0x0 to 0x290 (656) */
-                       speed = (value / 100);
-                       buf[1] = speed >> 8;
-                       buf[0] = speed & 0xff;
-                       break;
-               case 720:
-               case 730:
-               case 740:
-               case 750:
-                       /* speed seems to range from 0x0 to 0xff */
-                       buf[1] = 0;
-                       buf[0] = value >> 8;
-                       break;
-               }
-
-               ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
-       }
-       return ret;
-}      
-
-
-/* POWER */
-
-int pwc_camera_power(struct pwc_device *pdev, int power)
-{
-       char buf;
-
-       if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
-               return 0;       /* Not supported by Nala or Timon < release 6 */
-
-       if (power)
-               buf = 0x00; /* active */
-       else
-               buf = 0xFF; /* power save */
-       return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1);
-}
-
-
-
-/* private calls */
-
-static inline int pwc_restore_user(struct pwc_device *pdev)
-{
-       char buf; /* dummy */
-       return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
-}
-
-static inline int pwc_save_user(struct pwc_device *pdev)
-{
-       char buf; /* dummy */
-       return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
-}
-
-static inline int pwc_restore_factory(struct pwc_device *pdev)
-{
-       char buf; /* dummy */
-       return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
-}
-
- /* ************************************************* */
- /* Patch by Alvarado: (not in the original version   */
-
- /*
-  * the camera recognizes modes from 0 to 4:
-  *
-  * 00: indoor (incandescant lighting)
-  * 01: outdoor (sunlight)
-  * 02: fluorescent lighting
-  * 03: manual
-  * 04: auto
-  */ 
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
-{
-       char buf;
-       int ret;
-       
-       if (mode < 0)
-           mode = 0;
-       
-       if (mode > 4)
-           mode = 4;
-       
-       buf = mode & 0x07; /* just the lowest three bits */
-       
-       ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1);
-       
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int pwc_get_awb(struct pwc_device *pdev)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1);
-
-       if (ret < 0) 
-               return ret;
-       return buf;
-}
-
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
-{
-        unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
-}
-
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
-{
-       unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
-}
-
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-/* The following two functions are different, since they only read the
-   internal red/blue gains, which may be different from the manual 
-   gains set or read above.
- */   
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
-{
-       unsigned char buf;
-       
-       /* useful range is 0x01..0x20 */
-       buf = speed / 0x7f0;
-       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
-}
-
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf * 0x7f0;
-       return 0;
-}
-
-
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
-{
-       unsigned char buf;
-       
-       /* useful range is 0x01..0x3F */
-       buf = (delay >> 10);
-       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
-}
-
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf << 10;
-       return 0;
-}
-
-
-int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
-{
-       unsigned char buf[2];
-
-       if (pdev->type < 730)
-               return 0;
-       on_value /= 100;
-       off_value /= 100;
-       if (on_value < 0)
-               on_value = 0;
-       if (on_value > 0xff)
-               on_value = 0xff;
-       if (off_value < 0)
-               off_value = 0;
-       if (off_value > 0xff)
-               off_value = 0xff;
-
-       buf[0] = on_value;
-       buf[1] = off_value;
-
-       return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
-}
-
-static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
-{
-       unsigned char buf[2];
-       int ret;
-       
-       if (pdev->type < 730) {
-               *on_value = -1;
-               *off_value = -1;
-               return 0;
-       }
-
-       ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
-       if (ret < 0)
-               return ret;
-       *on_value = buf[0] * 100;
-       *off_value = buf[1] * 100;
-       return 0;
-}
-
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
-{
-       unsigned char buf;
-       int ret;
-       
-       if (contour < 0)
-               buf = 0xff; /* auto contour on */
-       else
-               buf = 0x0; /* auto contour off */
-       ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       
-       if (contour < 0)
-               return 0;
-       if (contour > 0xffff)
-               contour = 0xffff;
-       
-       buf = (contour >> 10); /* contour preset is [0..3f] */
-       ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
-       if (ret < 0)    
-               return ret;     
-       return 0;
-}
-
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-
-       if (buf == 0) {
-               /* auto mode off, query current preset value */
-               ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
-               if (ret < 0)    
-                       return ret;
-               *contour = buf << 10;
-       }
-       else
-               *contour = -1;
-       return 0;
-}
-
-
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
-{
-       unsigned char buf;
-       
-       if (backlight)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
-}
-
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
-{
-       int ret;
-       unsigned char buf;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *backlight = buf;
-       return 0;
-}
-
-
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
-{
-       unsigned char buf;
-       
-       if (flicker)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
-}
-
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
-{
-       int ret;
-       unsigned char buf;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *flicker = buf;
-       return 0;
-}
-
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
-{
-       unsigned char buf;
-
-       if (noise < 0)
-               noise = 0;
-       if (noise > 3)
-               noise = 3;
-       buf = noise;
-       return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
-}
-
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
-{
-       int ret;
-       unsigned char buf;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *noise = buf;
-       return 0;
-}
-
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
-{
-       unsigned char buf;
-       
-       buf = flags & 0x03; // only lower two bits are currently used
-       return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
-}
-
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
-{
-       unsigned char buf[4];
-       
-       /* set new relative angle; angles are expressed in degrees * 100,
-          but cam as .5 degree resolution, hence divide by 200. Also
-          the angle must be multiplied by 64 before it's send to
-          the cam (??)
-        */
-       pan  =  64 * pan  / 100;
-       tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
-       buf[0] = pan & 0xFF;
-       buf[1] = (pan >> 8) & 0xFF;
-       buf[2] = tilt & 0xFF;
-       buf[3] = (tilt >> 8) & 0xFF;
-       return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
-}
-
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
-{
-       int ret;
-       unsigned char buf[5];
-       
-       ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5);
-       if (ret < 0)
-               return ret;
-       status->status = buf[0] & 0x7; // 3 bits are used for reporting
-       status->time_pan = (buf[1] << 8) + buf[2];
-       status->time_tilt = (buf[3] << 8) + buf[4];
-       return 0;
-}
-
-
-int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
-{
-       unsigned char buf;
-       int ret = -1, request;
-       
-       if (pdev->type < 675)
-               request = SENSOR_TYPE_FORMATTER1;
-       else if (pdev->type < 730)
-               return -1; /* The Vesta series doesn't have this call */
-       else
-               request = SENSOR_TYPE_FORMATTER2;
-       
-       ret = RecvControlMsg(GET_STATUS_CTL, request, 1);
-       if (ret < 0)
-               return ret;
-       if (pdev->type < 675)
-               *sensor = buf | 0x100;
-       else
-               *sensor = buf;
-       return 0;
-}
-
-
- /* End of Add-Ons                                    */
- /* ************************************************* */
-
-
-int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
-{
-       int ret = 0;
-
-       switch(cmd) {
-       case VIDIOCPWCRUSER:
-       {
-               if (pwc_restore_user(pdev))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCSUSER:
-       {
-               if (pwc_save_user(pdev))
-                       ret = -EINVAL;
-               break;
-       }
-               
-       case VIDIOCPWCFACTORY:
-       {
-               if (pwc_restore_factory(pdev))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCSCQUAL:
-       {       
-               int *qual = arg;
-
-               if (*qual < 0 || *qual > 3)
-                       ret = -EINVAL;
-               else
-                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
-               if (ret >= 0)
-                       pdev->vcompression = *qual;
-               break;
-       }
-       
-       case VIDIOCPWCGCQUAL:
-       {
-               int *qual = arg;
-               *qual = pdev->vcompression;
-               break;
-       }
-       
-       case VIDIOCPWCPROBE:
-       {
-               struct pwc_probe *probe = arg;
-               strcpy(probe->name, pdev->vdev->name);
-               probe->type = pdev->type;
-               break;
-       }
-
-       case VIDIOCPWCGSERIAL:
-       {
-               struct pwc_serial *serial = arg;
-               strcpy(serial->serial, pdev->serial);
-               break;
-       }
-
-       case VIDIOCPWCSAGC:
-       {
-               int *agc = arg;
-               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCGAGC:
-       {
-               int *agc = arg;
-               
-               if (pwc_get_agc(pdev, agc))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCSSHUTTER:
-       {
-               int *shutter_speed = arg;
-               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
-               break;
-       }
-       
-        case VIDIOCPWCSAWB:
-       {
-               struct pwc_whitebalance *wb = arg;
-               
-               ret = pwc_set_awb(pdev, wb->mode);
-               if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
-                       pwc_set_red_gain(pdev, wb->manual_red);
-                       pwc_set_blue_gain(pdev, wb->manual_blue);
-               }
-               break;
-       }
-
-       case VIDIOCPWCGAWB:
-       {
-               struct pwc_whitebalance *wb = arg;
-
-               memset(wb, 0, sizeof(struct pwc_whitebalance));
-               wb->mode = pwc_get_awb(pdev);
-               if (wb->mode < 0)
-                       ret = -EINVAL;
-               else {
-                       if (wb->mode == PWC_WB_MANUAL) {
-                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
-                               if (ret < 0)
-                                       break;
-                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-                       if (wb->mode == PWC_WB_AUTO) {
-                               ret = pwc_read_red_gain(pdev, &wb->read_red);
-                               if (ret < 0)
-                                       break;
-                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-               }
-               break;
-       }
-       
-       case VIDIOCPWCSAWBSPEED:
-       {
-               struct pwc_wb_speed *wbs = arg;
-               
-               if (wbs->control_speed > 0) {
-                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
-               }
-               if (wbs->control_delay > 0) {
-                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
-               }
-               break;
-       }
-       
-       case VIDIOCPWCGAWBSPEED:
-       {
-               struct pwc_wb_speed *wbs = arg;
-               
-               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
-               if (ret < 0)
-                       break;
-               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
-               if (ret < 0)
-                       break;
-               break;
-       }
-
-        case VIDIOCPWCSLED:
-       {
-               struct pwc_leds *leds = arg;
-               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
-               break;
-       }
-
-
-       case VIDIOCPWCGLED:
-       {
-               struct pwc_leds *leds = arg;
-               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
-               break;
-       }
-
-       case VIDIOCPWCSCONTOUR:
-       {
-               int *contour = arg;
-               ret = pwc_set_contour(pdev, *contour);
-               break;
-       }
-                       
-       case VIDIOCPWCGCONTOUR:
-       {
-               int *contour = arg;
-               ret = pwc_get_contour(pdev, contour);
-               break;
-       }
-       
-       case VIDIOCPWCSBACKLIGHT:
-       {
-               int *backlight = arg;
-               ret = pwc_set_backlight(pdev, *backlight);
-               break;
-       }
-
-       case VIDIOCPWCGBACKLIGHT:
-       {
-               int *backlight = arg;
-               ret = pwc_get_backlight(pdev, backlight);
-               break;
-       }
-       
-       case VIDIOCPWCSFLICKER:
-       {
-               int *flicker = arg;
-               ret = pwc_set_flicker(pdev, *flicker);
-               break;
-       }
-
-       case VIDIOCPWCGFLICKER:
-       {
-               int *flicker = arg;
-               ret = pwc_get_flicker(pdev, flicker);
-               break;
-       }
-       
-       case VIDIOCPWCSDYNNOISE:
-       {
-               int *dynnoise = arg;
-               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
-               break;
-       }
-       
-       case VIDIOCPWCGDYNNOISE:
-       {
-               int *dynnoise = arg;
-               ret = pwc_get_dynamic_noise(pdev, dynnoise);
-               break;
-       }
-
-       case VIDIOCPWCGREALSIZE:
-       {
-               struct pwc_imagesize *size = arg;
-               size->width = pdev->image.x;
-               size->height = pdev->image.y;
-               break;
-       }
-       
-       case VIDIOCPWCMPTRESET:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       int *flags = arg;
-
-                       ret = pwc_mpt_reset(pdev, *flags);
-                       if (ret >= 0)
-                       {
-                               pdev->pan_angle = 0;
-                               pdev->tilt_angle = 0;
-                       }
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;          
-       }
-       
-       case VIDIOCPWCMPTGRANGE:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_range *range = arg;
-                       *range = pdev->angle_range;
-               }
-               else
-               {       
-                       ret = -ENXIO;
-               }
-               break;
-       }
-       
-       case VIDIOCPWCMPTSANGLE:
-       {
-               int new_pan, new_tilt;
-               
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_angles *angles = arg;
-                       /* The camera can only set relative angles, so
-                          do some calculations when getting an absolute angle .
-                        */
-                       if (angles->absolute)
-                       {
-                               new_pan  = angles->pan;
-                               new_tilt = angles->tilt;
-                       }
-                       else
-                       {
-                               new_pan  = pdev->pan_angle  + angles->pan;
-                               new_tilt = pdev->tilt_angle + angles->tilt;
-                       }
-                       /* check absolute ranges */
-                       if (new_pan  < pdev->angle_range.pan_min  ||
-                           new_pan  > pdev->angle_range.pan_max  ||
-                           new_tilt < pdev->angle_range.tilt_min ||
-                           new_tilt > pdev->angle_range.tilt_max)
-                       {
-                               ret = -ERANGE;
-                       }
-                       else
-                       {
-                               /* go to relative range, check again */
-                               new_pan  -= pdev->pan_angle;
-                               new_tilt -= pdev->tilt_angle;
-                               /* angles are specified in degrees * 100, thus the limit = 36000 */
-                               if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
-                                       ret = -ERANGE;
-                       }
-                       if (ret == 0) /* no errors so far */
-                       {
-                               ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
-                               if (ret >= 0)
-                               {
-                                       pdev->pan_angle  += new_pan;
-                                       pdev->tilt_angle += new_tilt;
-                               }
-                               if (ret == -EPIPE) /* stall -> out of range */
-                                       ret = -ERANGE;                          
-                       }
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCMPTGANGLE:
-       {
-               
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_angles *angles = arg;
-
-                       angles->absolute = 1;
-                       angles->pan  = pdev->pan_angle;
-                       angles->tilt = pdev->tilt_angle;
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-       case VIDIOCPWCMPTSTATUS:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_status *status = arg;
-                       ret = pwc_mpt_get_status(pdev, status);
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCGVIDCMD:
-       {
-               struct pwc_video_command *cmd = arg;
-               
-                cmd->type = pdev->type;
-               cmd->release = pdev->release;
-               cmd->command_len = pdev->cmd_len;
-               memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
-               cmd->bandlength = pdev->vbandlength;
-               cmd->frame_size = pdev->frame_size;
-               break;
-       }
-       /*
-       case VIDIOCPWCGVIDTABLE:
-       {
-               struct pwc_table_init_buffer *table = arg;
-               table->len = pdev->cmd_len;
-               memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
-               break;
-       }
-       */
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-       
-       if (ret > 0)
-               return 0;
-       return ret;
-}
-
-
-
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
deleted file mode 100644 (file)
index 90eb260..0000000
+++ /dev/null
@@ -1,2205 +0,0 @@
-/* Linux driver for Philips webcam
-   USB and Video4Linux interface part.
-   (C) 1999-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-*/
-
-/*  
-   This code forms the interface between the USB layers and the Philips
-   specific stuff. Some adanved stuff of the driver falls under an
-   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
-   is thus not distributed in source form. The binary pwcx.o module 
-   contains the code that falls under the NDA.
-   
-   In case you're wondering: 'pwc' stands for "Philips WebCam", but 
-   I really didn't want to type 'philips_web_cam' every time (I'm lazy as
-   any Linux kernel hacker, but I don't like uncomprehensible abbreviations
-   without explanation).
-   
-   Oh yes, convention: to disctinguish between all the various pointers to
-   device-structures, I use these names for the pointer variables:
-   udev: struct usb_device *
-   vdev: struct video_device *
-   pdev: struct pwc_devive *
-*/
-
-/* Contributors:
-   - Alvarado: adding whitebalance code
-   - Alistar Moire: QuickCam 3000 Pro device/product ID
-   - Tony Hoyle: Creative Labs Webcam 5 device/product ID
-   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
-   - Jk Fang: Sotec Afina Eye ID
-   - Xavier Roche: QuickCam Pro 4000 ID
-   - Jens Knudsen: QuickCam Zoom ID
-   - J. Debert: QuickCam for Notebooks ID
-*/
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <asm/io.h>
-
-#include "pwc.h"
-#include "pwc-ioctl.h"
-#include "pwc-kiara.h"
-#include "pwc-timon.h"
-#include "pwc-uncompress.h"
-
-/* Function prototypes and driver templates */
-
-/* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
-       { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
-       { USB_DEVICE(0x0471, 0x0303) },
-       { USB_DEVICE(0x0471, 0x0304) },
-       { USB_DEVICE(0x0471, 0x0307) },
-       { USB_DEVICE(0x0471, 0x0308) },
-       { USB_DEVICE(0x0471, 0x030C) },
-       { USB_DEVICE(0x0471, 0x0310) },
-       { USB_DEVICE(0x0471, 0x0311) },
-       { USB_DEVICE(0x0471, 0x0312) },
-       { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
-       { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
-       { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
-       { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
-       { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
-       { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
-       { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
-       { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
-       { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
-       { USB_DEVICE(0x055D, 0x9001) },
-       { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
-       { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
-       { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
-       { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
-       { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
-       { USB_DEVICE(0x0d81, 0x1900) },
-       { }
-};
-MODULE_DEVICE_TABLE(usb, pwc_device_table);
-
-static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
-static void usb_pwc_disconnect(struct usb_interface *intf);
-
-static struct usb_driver pwc_driver = {
-       .name =                 "Philips webcam",       /* name */
-       .id_table =             pwc_device_table,
-       .probe =                usb_pwc_probe,          /* probe() */
-       .disconnect =           usb_pwc_disconnect,     /* disconnect() */
-};
-
-#define MAX_DEV_HINTS  20
-#define MAX_ISOC_ERRORS        20
-
-static int default_size = PSZ_QCIF;
-static int default_fps = 10;
-static int default_fbufs = 3;   /* Default number of frame buffers */
-static int default_mbufs = 2;  /* Default number of mmap() buffers */
-       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
-static int power_save = 0;
-static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
-static struct {
-       int type;
-       char serial_number[30];
-       int device_node;
-       struct pwc_device *pdev;
-} device_hint[MAX_DEV_HINTS];
-
-/***/
-
-static int pwc_video_open(struct inode *inode, struct file *file);
-static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
-                         size_t count, loff_t *ppos);
-static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
-static int  pwc_video_ioctl(struct inode *inode, struct file *file,
-                           unsigned int ioctlnr, unsigned long arg);
-static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-
-static struct file_operations pwc_fops = {
-       .owner =        THIS_MODULE,
-       .open =         pwc_video_open,
-       .release =      pwc_video_close,
-       .read =         pwc_video_read,
-       .poll =         pwc_video_poll,
-       .mmap =         pwc_video_mmap,
-       .ioctl =        pwc_video_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-static struct video_device pwc_template = {
-       .owner =        THIS_MODULE,
-       .name =         "Philips Webcam",       /* Filled in later */
-       .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_PWC,
-       .release =      video_device_release,
-       .fops =         &pwc_fops,
-       .minor =        -1,
-};
-
-/***************************************************************************/
-
-/* Okay, this is some magic that I worked out and the reasoning behind it...
-
-   The biggest problem with any USB device is of course: "what to do 
-   when the user unplugs the device while it is in use by an application?"
-   We have several options:
-   1) Curse them with the 7 plagues when they do (requires divine intervention)
-   2) Tell them not to (won't work: they'll do it anyway)
-   3) Oops the kernel (this will have a negative effect on a user's uptime)
-   4) Do something sensible.
-   
-   Of course, we go for option 4.
-
-   It happens that this device will be linked to two times, once from
-   usb_device and once from the video_device in their respective 'private'
-   pointers. This is done when the device is probed() and all initialization
-   succeeded. The pwc_device struct links back to both structures.
-
-   When a device is unplugged while in use it will be removed from the 
-   list of known USB devices; I also de-register it as a V4L device, but 
-   unfortunately I can't free the memory since the struct is still in use
-   by the file descriptor. This free-ing is then deferend until the first
-   opportunity. Crude, but it works.
-   
-   A small 'advantage' is that if a user unplugs the cam and plugs it back
-   in, it should get assigned the same video device minor, but unfortunately
-   it's non-trivial to re-link the cam back to the video device... (that 
-   would surely be magic! :))
-*/
-
-/***************************************************************************/
-/* Private functions */
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr) 
-{
-        unsigned long kva, ret;
-
-       kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-       kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-       ret = __pa(kva);
-        return ret;
-}
-
-static void * rvmalloc(unsigned long size)
-{
-       void * mem;
-       unsigned long adr;
-
-       size=PAGE_ALIGN(size);
-        mem=vmalloc_32(size);
-       if (mem) 
-       {
-               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-               adr=(unsigned long) mem;
-               while (size > 0) 
-                {
-                       SetPageReserved(vmalloc_to_page((void *)adr));
-                       adr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-       }
-       return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-        unsigned long adr;
-
-       if (mem) 
-       {
-               adr=(unsigned long) mem;
-               while ((long) size > 0) 
-                {
-                       ClearPageReserved(vmalloc_to_page((void *)adr));
-                       adr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-               vfree(mem);
-       }
-}
-
-
-
-
-static int pwc_allocate_buffers(struct pwc_device *pdev)
-{
-       int i;
-       void *kbuf;
-
-       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
-
-       if (pdev == NULL)
-               return -ENXIO;
-               
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("allocate_buffers(): magic failed.\n");
-               return -ENXIO;
-       }
-#endif 
-       /* Allocate Isochronous pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
-                       if (kbuf == NULL) {
-                               Err("Failed to allocate iso buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
-                       pdev->sbuf[i].data = kbuf;
-                       memset(kbuf, 0, ISO_BUFFER_SIZE);
-               }
-       }
-
-       /* Allocate frame buffer structure */
-       if (pdev->fbuf == NULL) {
-               kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
-               if (kbuf == NULL) {
-                       Err("Failed to allocate frame buffer structure.\n");
-                       return -ENOMEM;
-               }
-               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
-               pdev->fbuf = kbuf;
-               memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
-       }
-       /* create frame buffers, and make circular ring */
-       for (i = 0; i < default_fbufs; i++) {
-               if (pdev->fbuf[i].data == NULL) {
-                       kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
-                       if (kbuf == NULL) {
-                               Err("Failed to allocate frame buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
-                       pdev->fbuf[i].data = kbuf;
-                       memset(kbuf, 128, PWC_FRAME_SIZE);
-               }
-       }
-       
-       /* Allocate decompressor table space */
-       kbuf = NULL;
-       switch (pdev->type)
-        {
-         case 675:
-         case 680:
-         case 690:
-         case 720:
-         case 730:
-         case 740:
-         case 750:
-#if 0    
-           Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
-           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);       /* Timon & Kiara */
-           break;
-         case 645:
-         case 646:
-           /* TODO & FIXME */
-           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
-           break;
-#endif  
-       ;
-        }
-       pdev->decompress_data = kbuf;
-       
-       /* Allocate image buffer; double buffer for mmap() */
-       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
-       if (kbuf == NULL) {
-               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
-               return -ENOMEM;
-       }
-       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
-       pdev->image_data = kbuf;
-       for (i = 0; i < default_mbufs; i++)
-               pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
-       for (; i < MAX_IMAGES; i++)
-               pdev->image_ptr[i] = NULL;
-
-       kbuf = NULL;
-         
-       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
-       return 0;
-}
-
-static void pwc_free_buffers(struct pwc_device *pdev)
-{
-       int i;
-
-       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
-
-       if (pdev == NULL)
-               return;
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("free_buffers(): magic failed.\n");
-               return;
-       }
-#endif 
-
-       /* Release Iso-pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++)
-               if (pdev->sbuf[i].data != NULL) {
-                       Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
-                       kfree(pdev->sbuf[i].data);
-                       pdev->sbuf[i].data = NULL;
-               }
-
-       /* The same for frame buffers */
-       if (pdev->fbuf != NULL) {
-               for (i = 0; i < default_fbufs; i++) {
-                       if (pdev->fbuf[i].data != NULL) {
-                               Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
-                               vfree(pdev->fbuf[i].data);
-                               pdev->fbuf[i].data = NULL;
-                       }
-               }
-               kfree(pdev->fbuf);
-               pdev->fbuf = NULL;
-       }
-
-       /* Intermediate decompression buffer & tables */
-       if (pdev->decompress_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
-               kfree(pdev->decompress_data);
-               pdev->decompress_data = NULL;
-       }
-       pdev->decompressor = NULL;
-
-       /* Release image buffers */
-       if (pdev->image_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
-               rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
-       }
-       pdev->image_data = NULL;
-       
-       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
-}
-
-/* The frame & image buffer mess. 
-
-   Yes, this is a mess. Well, it used to be simple, but alas...  In this
-   module, 3 buffers schemes are used to get the data from the USB bus to
-   the user program. The first scheme involves the ISO buffers (called thus
-   since they transport ISO data from the USB controller), and not really
-   interesting. Suffices to say the data from this buffer is quickly 
-   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
-   frame buffer.
-
-   The frame buffer is the second scheme, and is the central element here.
-   It collects the data from a single frame from the camera (hence, the
-   name). Frames are delimited by the USB camera with a short USB packet,
-   so that's easy to detect. The frame buffers form a list that is filled
-   by the camera+USB controller and drained by the user process through
-   either read() or mmap().
-
-   The image buffer is the third scheme, in which frames are decompressed
-   and converted into planar format. For mmap() there is more than
-   one image buffer available.
-
-   The frame buffers provide the image buffering. In case the user process
-   is a bit slow, this introduces lag and some undesired side-effects.
-   The problem arises when the frame buffer is full. I used to drop the last
-   frame, which makes the data in the queue stale very quickly. But dropping
-   the frame at the head of the queue proved to be a litte bit more difficult.
-   I tried a circular linked scheme, but this introduced more problems than
-   it solved.
-
-   Because filling and draining are completely asynchronous processes, this
-   requires some fiddling with pointers and mutexes.
-
-   Eventually, I came up with a system with 2 lists: an 'empty' frame list
-   and a 'full' frame list:
-     * Initially, all frame buffers but one are on the 'empty' list; the one
-       remaining buffer is our initial fill frame.
-     * If a frame is needed for filling, we try to take it from the 'empty' 
-       list, unless that list is empty, in which case we take the buffer at 
-       the head of the 'full' list.
-     * When our fill buffer has been filled, it is appended to the 'full'
-       list.
-     * If a frame is needed by read() or mmap(), it is taken from the head of
-       the 'full' list, handled, and then appended to the 'empty' list. If no
-       buffer is present on the 'full' list, we wait.
-   The advantage is that the buffer that is currently being decompressed/
-   converted, is on neither list, and thus not in our way (any other scheme
-   I tried had the problem of old data lingering in the queue).
-
-   Whatever strategy you choose, it always remains a tradeoff: with more
-   frame buffers the chances of a missed frame are reduced. On the other
-   hand, on slower machines it introduces lag because the queue will
-   always be full.
- */
-
-/**
-  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
- */
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
-{
-       int ret;
-       unsigned long flags;
-
-       ret = 0;
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       if (pdev->fill_frame != NULL) {
-               /* append to 'full' list */
-               if (pdev->full_frames == NULL) {
-                       pdev->full_frames = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->full_frames;
-               }
-               else {
-                       pdev->full_frames_tail->next = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->fill_frame;
-               }
-       }
-       if (pdev->empty_frames != NULL) {
-               /* We have empty frames available. That's easy */
-               pdev->fill_frame = pdev->empty_frames;
-               pdev->empty_frames = pdev->empty_frames->next;
-       }
-       else {
-               /* Hmm. Take it from the full list */
-#if PWC_DEBUG
-               /* sanity check */
-               if (pdev->full_frames == NULL) {
-                       Err("Neither empty or full frames available!\n");
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       return -EINVAL;
-               }
-#endif
-               pdev->fill_frame = pdev->full_frames;
-               pdev->full_frames = pdev->full_frames->next;
-               ret = 1;
-       }
-       pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
-       Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
-       pdev->fill_frame->sequence = pdev->sequence++;
-#endif
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-
-/**
-  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
-
-  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
- */
-static void pwc_reset_buffers(struct pwc_device *pdev)
-{
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       pdev->full_frames = NULL;
-       pdev->full_frames_tail = NULL;
-       for (i = 0; i < default_fbufs; i++) {
-               pdev->fbuf[i].filled = 0;
-               if (i > 0)
-                       pdev->fbuf[i].next = &pdev->fbuf[i - 1];
-               else
-                       pdev->fbuf->next = NULL;
-       }
-       pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
-       pdev->empty_frames_tail = pdev->fbuf;
-       pdev->read_frame = NULL;
-       pdev->fill_frame = pdev->empty_frames;
-       pdev->empty_frames = pdev->empty_frames->next;
-
-       pdev->image_read_pos = 0;
-       pdev->fill_image = 0;
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-}
-
-
-/**
-  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
- */
-static int pwc_handle_frame(struct pwc_device *pdev)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       /* First grab our read_frame; this is removed from all lists, so
-          we can release the lock after this without problems */
-       if (pdev->read_frame != NULL) {
-               /* This can't theoretically happen */
-               Err("Huh? Read frame still in use?\n");
-       }
-       else {
-               if (pdev->full_frames == NULL) {
-                       Err("Woops. No frames ready.\n");
-               }
-               else {
-                       pdev->read_frame = pdev->full_frames;
-                       pdev->full_frames = pdev->full_frames->next;
-                       pdev->read_frame->next = NULL;
-               }
-
-               if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
-                       Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
-                       /* Decompression is a lenghty process, so it's outside of the lock.
-                          This gives the isoc_handler the opportunity to fill more frames
-                          in the mean time.
-                       */
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       ret = pwc_decompress(pdev);
-                       spin_lock_irqsave(&pdev->ptrlock, flags);
-
-                       /* We're done with read_buffer, tack it to the end of the empty buffer list */
-                       if (pdev->empty_frames == NULL) {
-                               pdev->empty_frames = pdev->read_frame;
-                               pdev->empty_frames_tail = pdev->empty_frames;
-                       }
-                       else {
-                               pdev->empty_frames_tail->next = pdev->read_frame;
-                               pdev->empty_frames_tail = pdev->read_frame;
-                       }
-                       pdev->read_frame = NULL;
-               }
-       }
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-/**
-  \brief Advance pointers of image buffer (after each user request)
-*/
-static inline void pwc_next_image(struct pwc_device *pdev)
-{
-       pdev->image_used[pdev->fill_image] = 0;
-       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
-}
-
-
-/* This gets called for the Isochronous pipe (video). This is done in
- * interrupt time, so it has to be fast, not crash, and not stall. Neat.
- */
-static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
-{
-       struct pwc_device *pdev;
-       int i, fst, flen;
-       int awake;
-       struct pwc_frame_buf *fbuf;
-       unsigned char *fillptr = NULL, *iso_buf = NULL;
-
-       awake = 0;
-       pdev = (struct pwc_device *)urb->context;
-       if (pdev == NULL) {
-               Err("isoc_handler() called with NULL device?!\n");
-               return;
-       }
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("isoc_handler() called with bad magic!\n");
-               return;
-       }
-#endif
-       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-               Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
-               return;
-       }
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
-               const char *errmsg;
-
-               errmsg = "Unknown";
-               switch(urb->status) {
-                       case -ENOSR:            errmsg = "Buffer error (overrun)"; break;
-                       case -EPIPE:            errmsg = "Stalled (device not responding)"; break;
-                       case -EOVERFLOW:        errmsg = "Babble (bad cable?)"; break;
-                       case -EPROTO:           errmsg = "Bit-stuff error (bad cable?)"; break;
-                       case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
-                       case -ETIMEDOUT:        errmsg = "NAK (device does not respond)"; break;
-               }
-               Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
-               /* Give up after a number of contiguous errors on the USB bus. 
-                  Appearantly something is wrong so we simulate an unplug event.
-                */
-               if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
-               {
-                       Info("Too many ISOC errors, bailing out.\n");
-                       pdev->error_status = EIO;
-                       awake = 1;
-                       wake_up_interruptible(&pdev->frameq);
-               }
-               goto handler_end; // ugly, but practical
-       }
-
-       fbuf = pdev->fill_frame;
-       if (fbuf == NULL) {
-               Err("pwc_isoc_handler without valid fill frame.\n");
-               awake = 1;
-               goto handler_end;
-       }
-       else {
-               fillptr = fbuf->data + fbuf->filled;
-       }
-
-       /* Reset ISOC error counter. We did get here, after all. */
-       pdev->visoc_errors = 0;
-
-       /* vsync: 0 = don't copy data
-                 1 = sync-hunt
-                 2 = synched
-        */
-       /* Compact data */
-       for (i = 0; i < urb->number_of_packets; i++) {
-               fst  = urb->iso_frame_desc[i].status;
-               flen = urb->iso_frame_desc[i].actual_length;
-               iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-               if (fst == 0) {
-                       if (flen > 0) { /* if valid data... */
-                               if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
-                                       pdev->vsync = 2;
-
-                                       /* ...copy data to frame buffer, if possible */
-                                       if (flen + fbuf->filled > pdev->frame_total_size) {
-                                               Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
-                                               pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
-                                               pdev->vframes_error++;
-                                       }
-                                       else {
-                                               memmove(fillptr, iso_buf, flen);
-                                               fillptr += flen;
-                                       }
-                               }
-                               fbuf->filled += flen;
-                       } /* ..flen > 0 */
-
-                       if (flen < pdev->vlast_packet_size) {
-                               /* Shorter packet... We probably have the end of an image-frame; 
-                                  wake up read() process and let select()/poll() do something.
-                                  Decompression is done in user time over there.
-                                */
-                               if (pdev->vsync == 2) {
-                                       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus 
-                                          frames on the USB wire after an exposure change. This conditition is 
-                                          however detected  in the cam and a bit is set in the header.
-                                        */
-                                       if (pdev->type == 730) {
-                                               unsigned char *ptr = (unsigned char *)fbuf->data;
-                                               
-                                               if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
-                                                       Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
-                                                       pdev->drop_frames += 2;
-                                                       pdev->vframes_error++;
-                                               }
-                                               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                                                       if (ptr[0] & 0x01)
-                                                               Info("Snapshot button pressed.\n");
-                                                       else
-                                                               Info("Snapshot button released.\n");
-                                               }
-                                               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
-                                                       if (ptr[0] & 0x02)
-                                                               Info("Image is mirrored.\n");
-                                                       else
-                                                               Info("Image is normal.\n");
-                                               }
-                                               pdev->vmirror = ptr[0] & 0x03;
-                                               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
-                                                  after a short frame; this condition is filtered out specifically. A 4 byte
-                                                  frame doesn't make sense anyway.
-                                                  So we get either this sequence: 
-                                                       drop_bit set -> 4 byte frame -> short frame -> good frame
-                                                  Or this one:
-                                                       drop_bit set -> short frame -> good frame
-                                                  So we drop either 3 or 2 frames in all!
-                                                */
-                                               if (fbuf->filled == 4)
-                                                       pdev->drop_frames++;
-                                       }
-
-                                       /* In case we were instructed to drop the frame, do so silently.
-                                          The buffer pointers are not updated either (but the counters are reset below).
-                                        */
-                                       if (pdev->drop_frames > 0)
-                                               pdev->drop_frames--;
-                                       else {
-                                               /* Check for underflow first */
-                                               if (fbuf->filled < pdev->frame_total_size) {
-                                                       Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
-                                                       pdev->vframes_error++;
-                                               }
-                                               else {
-                                                       /* Send only once per EOF */
-                                                       awake = 1; /* delay wake_ups */
-
-                                                       /* Find our next frame to fill. This will always succeed, since we
-                                                        * nick a frame from either empty or full list, but if we had to
-                                                        * take it from the full list, it means a frame got dropped.
-                                                        */
-                                                       if (pwc_next_fill_frame(pdev)) {
-                                                               pdev->vframes_dumped++;
-                                                               if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
-                                                                       if (pdev->vframes_dumped < 20)
-                                                                               Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
-                                                                       if (pdev->vframes_dumped == 20)
-                                                                               Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
-                                                               }
-                                                       }
-                                                       fbuf = pdev->fill_frame;
-                                               }
-                                       } /* !drop_frames */
-                                       pdev->vframe_count++;
-                               }
-                               fbuf->filled = 0;
-                               fillptr = fbuf->data;
-                               pdev->vsync = 1;
-                       } /* .. flen < last_packet_size */
-                       pdev->vlast_packet_size = flen;
-               } /* ..status == 0 */
-#if PWC_DEBUG
-               /* This is normally not interesting to the user, unless you are really debugging something */
-               else {
-                       static int iso_error = 0;
-                       iso_error++;
-                       if (iso_error < 20)
-                               Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
-               }
-#endif
-       }
-
-handler_end:
-       if (awake)
-               wake_up_interruptible(&pdev->frameq);
-
-       urb->dev = pdev->udev;
-       i = usb_submit_urb(urb, GFP_ATOMIC);
-       if (i != 0)
-               Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
-}
-
-
-static int pwc_isoc_init(struct pwc_device *pdev)
-{
-       struct usb_device *udev;
-       struct urb *urb;
-       int i, j, ret;
-
-       struct usb_interface *intf;
-       struct usb_host_interface *idesc = NULL;
-
-       if (pdev == NULL)
-               return -EFAULT;
-       if (pdev->iso_init)
-               return 0;
-       pdev->vsync = 0;
-       udev = pdev->udev;
-
-       /* Get the current alternate interface, adjust packet size */
-       if (!udev->actconfig)
-               return -EFAULT;
-
-       intf = usb_ifnum_to_if(udev, 0);
-       if (intf)
-               idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-               
-       if (!idesc)
-               return -EFAULT;
-
-       /* Search video endpoint */
-       pdev->vmax_packet_size = -1;
-       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
-               if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
-                       pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
-                       break;
-               }
-       
-       if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
-               Err("Failed to find packet size for video endpoint in current alternate setting.\n");
-               return -ENFILE; /* Odd error, that should be noticeable */
-       }
-
-       /* Set alternate interface */
-       ret = 0;
-       Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
-       ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
-               if (urb == NULL) {
-                       Err("Failed to allocate urb %d\n", i);
-                       ret = -ENOMEM;
-                       break;
-               }
-               pdev->sbuf[i].urb = urb;
-               Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
-       }
-       if (ret) {
-               /* De-allocate in reverse order */
-               while (i >= 0) {
-                       if (pdev->sbuf[i].urb != NULL)
-                               usb_free_urb(pdev->sbuf[i].urb);
-                       pdev->sbuf[i].urb = NULL;
-                       i--;
-               }
-               return ret;
-       }
-
-       /* init URB structure */        
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               urb = pdev->sbuf[i].urb;
-
-               urb->interval = 1; // devik
-               urb->dev = udev;
-               urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = pdev->sbuf[i].data;
-               urb->transfer_buffer_length = ISO_BUFFER_SIZE;
-               urb->complete = pwc_isoc_handler;
-               urb->context = pdev;
-               urb->start_frame = 0;
-               urb->number_of_packets = ISO_FRAMES_PER_DESC;
-               for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
-                       urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-                       urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
-               }
-       }
-
-       /* link */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
-               if (ret)
-                       Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
-               else
-                       Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
-       }
-
-       /* All is done... */
-       pdev->iso_init = 1;
-       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
-       return 0;
-}
-
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
-{
-       int i;
-
-       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
-       if (pdev == NULL)
-               return;
-
-       /* Unlinking ISOC buffers one by one */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               struct urb *urb;
-
-               urb = pdev->sbuf[i].urb;
-               if (urb != 0) {
-                       if (pdev->iso_init) {
-                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
-                               usb_kill_urb(urb);
-                       }
-                       Trace(TRACE_MEMORY, "Freeing URB\n");
-                       usb_free_urb(urb);
-                       pdev->sbuf[i].urb = NULL;
-               }
-       }
-
-       /* Stop camera, but only if we are sure the camera is still there (unplug
-          is signalled by EPIPE) 
-        */
-       if (pdev->error_status && pdev->error_status != EPIPE) {
-               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
-               usb_set_interface(pdev->udev, 0, 0);
-       }
-
-       pdev->iso_init = 0;
-       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
-}
-
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
-{
-       int ret, start;
-
-       /* Stop isoc stuff */
-       pwc_isoc_cleanup(pdev);
-       /* Reset parameters */
-       pwc_reset_buffers(pdev);
-       /* Try to set video mode... */
-       start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
-       if (ret) { 
-               Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
-               /* That failed... restore old mode (we know that worked) */
-               start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-               if (start) {
-                       Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
-               }
-       }
-       if (start == 0)
-       {
-               if (pwc_isoc_init(pdev) < 0)
-               {
-                       Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
-                       ret = -EAGAIN; /* let's try again, who knows if it works a second time */
-               }
-       }
-       pdev->drop_frames++; /* try to avoid garbage during switch */
-       return ret; /* Return original error code */
-}
-
-
-/***************************************************************************/
-/* Video4Linux functions */
-
-static int pwc_video_open(struct inode *inode, struct file *file)
-{
-       int i;
-       struct video_device *vdev = video_devdata(file);
-       struct pwc_device *pdev;
-
-       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
-       
-       pdev = (struct pwc_device *)vdev->priv;
-       if (pdev == NULL)
-               BUG();
-       if (pdev->vopen)
-               return -EBUSY;
-       
-       down(&pdev->modlock);
-       if (!pdev->usb_init) {
-               Trace(TRACE_OPEN, "Doing first time initialization.\n");
-               pdev->usb_init = 1;
-               
-               if (pwc_trace & TRACE_OPEN)
-               {
-                       /* Query sensor type */
-                       const char *sensor_type = NULL;
-                       int ret;
-
-                       ret = pwc_get_cmos_sensor(pdev, &i);
-                       if (ret >= 0)
-                       {
-                               switch(i) {
-                               case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
-                               case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
-                               case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
-                               case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
-                               case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
-                               case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
-                               case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
-                               case 0x40:  sensor_type = "UPA 1021 sensor"; break;
-                               case 0x100: sensor_type = "VGA sensor"; break;
-                               case 0x101: sensor_type = "PAL MR sensor"; break;
-                               default:    sensor_type = "unknown type of sensor"; break;
-                               }
-                       }
-                       if (sensor_type != NULL)
-                               Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
-               }
-       }
-
-       /* Turn on camera */
-       if (power_save) {
-               i = pwc_camera_power(pdev, 1);
-               if (i < 0)
-                       Info("Failed to restore power to the camera! (%d)\n", i);
-       }
-       /* Set LED on/off time */
-       if (pwc_set_leds(pdev, led_on, led_off) < 0)
-               Info("Failed to set LED on/off time.\n");
-       
-       pwc_construct(pdev); /* set min/max sizes correct */
-
-       /* So far, so good. Allocate memory. */
-       i = pwc_allocate_buffers(pdev);
-       if (i < 0) {
-               Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
-               up(&pdev->modlock);
-               return i;
-       }
-       
-       /* Reset buffers & parameters */
-       pwc_reset_buffers(pdev);
-       for (i = 0; i < default_mbufs; i++)
-               pdev->image_used[i] = 0;
-       pdev->vframe_count = 0;
-       pdev->vframes_dumped = 0;
-       pdev->vframes_error = 0;
-       pdev->visoc_errors = 0;
-       pdev->error_status = 0;
-#if PWC_DEBUG
-       pdev->sequence = 0;
-#endif
-       pwc_construct(pdev); /* set min/max sizes correct */
-
-       /* Set some defaults */
-       pdev->vsnapshot = 0;
-
-       /* Start iso pipe for video; first try the last used video size
-          (or the default one); if that fails try QCIF/10 or QSIF/10;
-          it that fails too, give up.
-        */
-       i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
-       if (i)  {
-               Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
-               if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
-               else
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
-       }
-       if (i) {
-               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
-               up(&pdev->modlock);
-               return i;
-       }
-       
-       i = pwc_isoc_init(pdev);
-       if (i) {
-               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
-               up(&pdev->modlock);
-               return i;
-       }
-
-       pdev->vopen++;
-       file->private_data = vdev;
-       up(&pdev->modlock);
-       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
-       return 0;
-}
-
-/* Note that all cleanup is done in the reverse order as in _open */
-static int pwc_video_close(struct inode *inode, struct file *file)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int i;
-
-       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
-
-       pdev = (struct pwc_device *)vdev->priv;
-       if (pdev->vopen == 0)
-               Info("video_close() called on closed device?\n");
-
-       /* Dump statistics, but only if a reasonable amount of frames were
-          processed (to prevent endless log-entries in case of snap-shot
-          programs)
-        */
-       if (pdev->vframe_count > 20)
-               Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
-
-       switch (pdev->type)
-        {
-         case 675:
-         case 680:
-         case 690:
-         case 720:
-         case 730:
-         case 740:
-         case 750:
-/*         pwc_dec23_exit();   *//* Timon & Kiara */
-           break;
-         case 645:
-         case 646:
-/*         pwc_dec1_exit(); */
-           break;
-        }
-
-       pwc_isoc_cleanup(pdev);
-       pwc_free_buffers(pdev);
-
-       /* Turn off LEDS and power down camera, but only when not unplugged */
-       if (pdev->error_status != EPIPE) {
-               /* Turn LEDs off */
-               if (pwc_set_leds(pdev, 0, 0) < 0)
-                       Info("Failed to set LED on/off time.\n");
-               if (power_save) {
-                       i = pwc_camera_power(pdev, 0);
-                       if (i < 0)
-                               Err("Failed to power down camera (%d)\n", i);
-               }
-       }
-       pdev->vopen = 0;
-       Trace(TRACE_OPEN, "<< video_close()\n");
-       return 0;
-}
-
-/*
- *     FIXME: what about two parallel reads ????
- *      ANSWER: Not supported. You can't open the device more than once,
-                despite what the V4L1 interface says. First, I don't see
-                the need, second there's no mechanism of alerting the
-                2nd/3rd/... process of events like changing image size.
-                And I don't see the point of blocking that for the
-                2nd/3rd/... process.
-                In multi-threaded environments reading parallel from any
-                device is tricky anyhow.
- */
-
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
-                         size_t count, loff_t *ppos)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int noblock = file->f_flags & O_NONBLOCK;
-       DECLARE_WAITQUEUE(wait, current);
-        int bytes_to_read;
-
-       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-       if (pdev->error_status)
-               return -pdev->error_status; /* Something happened, report what. */
-
-       /* In case we're doing partial reads, we don't have to wait for a frame */
-       if (pdev->image_read_pos == 0) {
-               /* Do wait queueing according to the (doc)book */
-               add_wait_queue(&pdev->frameq, &wait);
-               while (pdev->full_frames == NULL) {
-                       /* Check for unplugged/etc. here */
-                       if (pdev->error_status) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               return -pdev->error_status ;
-                       }
-                       if (noblock) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               return -EWOULDBLOCK;
-                       }
-                       if (signal_pending(current)) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               return -ERESTARTSYS;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-               remove_wait_queue(&pdev->frameq, &wait);
-               set_current_state(TASK_RUNNING);
-                                                                                                                                                                                
-               /* Decompress and release frame */
-               if (pwc_handle_frame(pdev))
-                       return -EFAULT;
-       }
-
-       Trace(TRACE_READ, "Copying data to user space.\n");
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               bytes_to_read = pdev->frame_size;
-       else
-               bytes_to_read = pdev->view.size;
-
-       /* copy bytes to user space; we allow for partial reads */
-       if (count + pdev->image_read_pos > bytes_to_read)
-               count = bytes_to_read - pdev->image_read_pos;
-       if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
-               return -EFAULT;
-       pdev->image_read_pos += count;
-       if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
-               pdev->image_read_pos = 0;
-               pwc_next_image(pdev);
-       }
-       return count;
-}
-
-static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-
-       poll_wait(file, &pdev->frameq, wait);
-       if (pdev->error_status)
-               return POLLERR;
-       if (pdev->full_frames != NULL) /* we have frames waiting */
-               return (POLLIN | POLLRDNORM);
-
-       return 0;
-}
-
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-
-       switch (cmd) {
-               /* Query cabapilities */
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *caps = arg;
-
-                       strcpy(caps->name, vdev->name);
-                       caps->type = VID_TYPE_CAPTURE;
-                       caps->channels = 1;
-                       caps->audios = 1;
-                       caps->minwidth  = pdev->view_min.x;
-                       caps->minheight = pdev->view_min.y;
-                       caps->maxwidth  = pdev->view_max.x;
-                       caps->maxheight = pdev->view_max.y;
-                       break;
-               }
-
-               /* Channel functions (simulate 1 channel) */
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       v->flags = 0;
-                       v->tuners = 0;
-                       v->type = VIDEO_TYPE_CAMERA;
-                       strcpy(v->name, "Webcam");
-                       return 0;
-               }
-
-               case VIDIOCSCHAN:
-               {
-                       /* The spec says the argument is an integer, but
-                          the bttv driver uses a video_channel arg, which
-                          makes sense becasue it also has the norm flag.
-                        */
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-
-
-               /* Picture functions; contrast etc. */
-               case VIDIOCGPICT:
-               {
-                       struct video_picture *p = arg;
-                       int val;
-
-                       val = pwc_get_brightness(pdev);
-                       if (val >= 0)
-                               p->brightness = val;
-                       else
-                               p->brightness = 0xffff;
-                       val = pwc_get_contrast(pdev);
-                       if (val >= 0)
-                               p->contrast = val;
-                       else
-                               p->contrast = 0xffff;
-                       /* Gamma, Whiteness, what's the difference? :) */
-                       val = pwc_get_gamma(pdev);
-                       if (val >= 0)
-                               p->whiteness = val;
-                       else
-                               p->whiteness = 0xffff;
-                       val = pwc_get_saturation(pdev);
-                       if (val >= 0)
-                               p->colour = val;
-                       else
-                               p->colour = 0xffff;
-                       p->depth = 24;
-                       p->palette = pdev->vpalette;
-                       p->hue = 0xFFFF; /* N/A */
-                       break;
-               }
-
-               case VIDIOCSPICT:
-               {
-                       struct video_picture *p = arg;
-                       /*
-                        *      FIXME:  Suppose we are mid read
-                               ANSWER: No problem: the firmware of the camera
-                                       can handle brightness/contrast/etc
-                                       changes at _any_ time, and the palette
-                                       is used exactly once in the uncompress
-                                       routine.
-                        */
-                       pwc_set_brightness(pdev, p->brightness);
-                       pwc_set_contrast(pdev, p->contrast);
-                       pwc_set_gamma(pdev, p->whiteness);
-                       pwc_set_saturation(pdev, p->colour);
-                       if (p->palette && p->palette != pdev->vpalette) {
-                               switch (p->palette) {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               pdev->vpalette = p->palette;
-                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-                       break;
-               }
-
-               /* Window/size parameters */            
-               case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-                       
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = pdev->view.x;
-                       vw->height = pdev->view.y;
-                       vw->chromakey = 0;
-                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | 
-                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
-                       break;
-               }
-               
-               case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-                       int fps, snapshot, ret;
-
-                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
-                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
-                       if (fps == 0)
-                               fps = pdev->vframes;
-                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
-                               return 0;
-                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
-                       if (ret)
-                               return ret;
-                       break;          
-               }
-               
-               /* We don't have overlay support (yet) */
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb,0,sizeof(*vb));
-                       break;
-               }
-
-               /* mmap() functions */
-               case VIDIOCGMBUF:
-               {
-                       /* Tell the user program how much memory is needed for a mmap() */
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset(vm, 0, sizeof(*vm));
-                       vm->size = default_mbufs * pdev->len_per_image;
-                       vm->frames = default_mbufs; /* double buffering should be enough for most applications */
-                       for (i = 0; i < default_mbufs; i++)
-                               vm->offsets[i] = i * pdev->len_per_image;
-                       break;
-               }
-
-               case VIDIOCMCAPTURE:
-               {
-                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
-                       struct video_mmap *vm = arg;
-
-                       Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
-                       if (vm->frame < 0 || vm->frame >= default_mbufs)
-                               return -EINVAL;
-
-                       /* xawtv is nasty. It probes the available palettes
-                          by setting a very small image size and trying
-                          various palettes... The driver doesn't support
-                          such small images, so I'm working around it.
-                        */
-                       if (vm->format)
-                       {
-                               switch (vm->format)
-                               {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-
-                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
-                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
-                               int ret;
-
-                               Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
-                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                               if (ret)
-                                       return ret;
-                       } /* ... size mismatch */
-
-                       /* FIXME: should we lock here? */
-                       if (pdev->image_used[vm->frame])
-                               return -EBUSY;  /* buffer wasn't available. Bummer */
-                       pdev->image_used[vm->frame] = 1;
-
-                       /* Okay, we're done here. In the SYNC call we wait until a 
-                          frame comes available, then expand image into the given 
-                          buffer.
-                          In contrast to the CPiA cam the Philips cams deliver a
-                          constant stream, almost like a grabber card. Also,
-                          we have separate buffers for the rawdata and the image,
-                          meaning we can nearly always expand into the requested buffer.
-                        */
-                       Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
-                       break;
-               }
-
-               case VIDIOCSYNC:
-               {
-                       /* The doc says: "Whenever a buffer is used it should
-                          call VIDIOCSYNC to free this frame up and continue."
-                          
-                          The only odd thing about this whole procedure is 
-                          that MCAPTURE flags the buffer as "in use", and
-                          SYNC immediately unmarks it, while it isn't 
-                          after SYNC that you know that the buffer actually
-                          got filled! So you better not start a CAPTURE in
-                          the same frame immediately (use double buffering). 
-                          This is not a problem for this cam, since it has 
-                          extra intermediate buffers, but a hardware 
-                          grabber card will then overwrite the buffer 
-                          you're working on.
-                        */
-                       int *mbuf = arg;
-                       int ret;
-
-                       Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
-                       /* bounds check */
-                       if (*mbuf < 0 || *mbuf >= default_mbufs)
-                               return -EINVAL;
-                       /* check if this buffer was requested anyway */
-                       if (pdev->image_used[*mbuf] == 0)
-                               return -EINVAL;
-
-                       /* Add ourselves to the frame wait-queue.
-                          
-                          FIXME: needs auditing for safety.
-                          QUESTION: In what respect? I think that using the
-                                    frameq is safe now.
-                        */
-                       add_wait_queue(&pdev->frameq, &wait);
-                       while (pdev->full_frames == NULL) {
-                               if (pdev->error_status) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -pdev->error_status;
-                               }
-                       
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -ERESTARTSYS;
-                               }
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       }
-                       remove_wait_queue(&pdev->frameq, &wait);
-                       set_current_state(TASK_RUNNING);
-                               
-                       /* The frame is ready. Expand in the image buffer 
-                          requested by the user. I don't care if you 
-                          mmap() 5 buffers and request data in this order: 
-                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
-                          Grabber hardware may not be so forgiving.
-                        */
-                       Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
-                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
-                       /* Decompress, etc */
-                       ret = pwc_handle_frame(pdev);
-                       pdev->image_used[*mbuf] = 0;
-                       if (ret)
-                               return -EFAULT;
-                       break;
-               }
-               
-               case VIDIOCGAUDIO:
-               {
-                       struct video_audio *v = arg;
-                       
-                       strcpy(v->name, "Microphone");
-                       v->audio = -1; /* unknown audio minor */
-                       v->flags = 0;
-                       v->mode = VIDEO_SOUND_MONO;
-                       v->volume = 0;
-                       v->bass = 0;
-                       v->treble = 0;
-                       v->balance = 0x8000;
-                       v->step = 1;
-                       break;  
-               }
-               
-               case VIDIOCSAUDIO:
-               {
-                       /* Dummy: nothing can be set */
-                       break;
-               }
-               
-               case VIDIOCGUNIT:
-               {
-                       struct video_unit *vu = arg;
-                       
-                       vu->video = pdev->vdev->minor & 0x3F;
-                       vu->audio = -1; /* not known yet */
-                       vu->vbi = -1;
-                       vu->radio = -1;
-                       vu->teletext = -1;
-                       break;
-               }
-               default:
-                       return pwc_ioctl(pdev, cmd, arg);
-       } /* ..switch */
-       return 0;
-}      
-
-static int pwc_video_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
-}
-
-
-static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-       
-       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
-       pdev = vdev->priv;
-       
-       vma->vm_flags |= VM_IO;
-
-       pos = (unsigned long)pdev->image_data;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-/***************************************************************************/
-/* USB functions */
-
-/* This function gets called when a new device is plugged in or the usb core
- * is loaded.
- */
-
-static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct pwc_device *pdev = NULL;
-       int vendor_id, product_id, type_id;
-       int i, hint;
-       int features = 0;
-       int video_nr = -1; /* default: use next available device */
-       char serial_number[30], *name;
-
-       /* Check if we can handle this device */
-       Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", 
-               le16_to_cpu(udev->descriptor.idVendor),
-               le16_to_cpu(udev->descriptor.idProduct),
-               intf->altsetting->desc.bInterfaceNumber);
-
-       /* the interfaces are probed one by one. We are only interested in the
-          video interface (0) now.
-          Interface 1 is the Audio Control, and interface 2 Audio itself.
-        */
-       if (intf->altsetting->desc.bInterfaceNumber > 0)
-               return -ENODEV;
-
-       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
-       product_id = le16_to_cpu(udev->descriptor.idProduct);
-
-       if (vendor_id == 0x0471) {
-               switch (product_id) {
-               case 0x0302:
-                       Info("Philips PCA645VC USB webcam detected.\n");
-                       name = "Philips 645 webcam";
-                       type_id = 645;
-                       break;
-               case 0x0303:
-                       Info("Philips PCA646VC USB webcam detected.\n");
-                       name = "Philips 646 webcam";
-                       type_id = 646;
-                       break;
-               case 0x0304:
-                       Info("Askey VC010 type 2 USB webcam detected.\n");
-                       name = "Askey VC010 webcam";
-                       type_id = 646;
-                       break;
-               case 0x0307:
-                       Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
-                       name = "Philips 675 webcam";
-                       type_id = 675;
-                       break;
-               case 0x0308:
-                       Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
-                       name = "Philips 680 webcam";
-                       type_id = 680;
-                       break;
-               case 0x030C:
-                       Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
-                       name = "Philips 690 webcam";
-                       type_id = 690;
-                       break;
-               case 0x0310:
-                       Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
-                       name = "Philips 730 webcam";
-                       type_id = 730;
-                       break;
-               case 0x0311:
-                       Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
-                       name = "Philips 740 webcam";
-                       type_id = 740;
-                       break;
-               case 0x0312:
-                       Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
-                       name = "Philips 750 webcam";
-                       type_id = 750;
-                       break;
-               case 0x0313:
-                       Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
-                       name = "Philips 720K/40 webcam";
-                       type_id = 720;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x069A) {
-               switch(product_id) {
-               case 0x0001:
-                       Info("Askey VC010 type 1 USB webcam detected.\n");
-                       name = "Askey VC010 webcam";
-                       type_id = 645;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x046d) {
-               switch(product_id) {
-               case 0x08b0:
-                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
-                       name = "Logitech QuickCam Pro 3000";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b1:
-                       Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
-                       name = "Logitech QuickCam Notebook Pro";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b2:
-                       Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
-                       name = "Logitech QuickCam Pro 4000";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b3:
-                       Info("Logitech QuickCam Zoom USB webcam detected.\n");
-                       name = "Logitech QuickCam Zoom";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08B4:
-                       Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
-                       name = "Logitech QuickCam Zoom";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b5:
-                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
-                       name = "Logitech QuickCam Orbit";
-                       type_id = 740; /* CCD sensor */
-                       features |= FEATURE_MOTOR_PANTILT;
-                       break;
-               case 0x08b6:
-               case 0x08b7:
-               case 0x08b8:
-                       Info("Logitech QuickCam detected (reserved ID).\n");
-                       name = "Logitech QuickCam (res.)";
-                       type_id = 730; /* Assuming CMOS */
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-        }
-       else if (vendor_id == 0x055d) {
-               /* I don't know the difference between the C10 and the C30;
-                  I suppose the difference is the sensor, but both cameras
-                  work equally well with a type_id of 675
-                */
-               switch(product_id) {
-               case 0x9000:
-                       Info("Samsung MPC-C10 USB webcam detected.\n");
-                       name = "Samsung MPC-C10";
-                       type_id = 675;
-                       break;
-               case 0x9001:
-                       Info("Samsung MPC-C30 USB webcam detected.\n");
-                       name = "Samsung MPC-C30";
-                       type_id = 675;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x041e) {
-               switch(product_id) {
-               case 0x400c:
-                       Info("Creative Labs Webcam 5 detected.\n");
-                       name = "Creative Labs Webcam 5";
-                       type_id = 730;
-                       break;
-               case 0x4011:
-                       Info("Creative Labs Webcam Pro Ex detected.\n");
-                       name = "Creative Labs Webcam Pro Ex";
-                       type_id = 740;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x04cc) {
-               switch(product_id) {
-               case 0x8116:
-                       Info("Sotec Afina Eye USB webcam detected.\n");
-                       name = "Sotec Afina Eye";
-                       type_id = 730;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x06be) {
-               switch(product_id) {
-               case 0x8116:
-                       /* This is essentially the same cam as the Sotec Afina Eye */
-                       Info("AME Co. Afina Eye USB webcam detected.\n");
-                       name = "AME Co. Afina Eye";
-                       type_id = 750;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       
-       }
-       else if (vendor_id == 0x0d81) {
-               switch(product_id) {
-               case 0x1900:
-                       Info("Visionite VCS-UC300 USB webcam detected.\n");
-                       name = "Visionite VCS-UC300";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x1910:
-                       Info("Visionite VCS-UM100 USB webcam detected.\n");
-                       name = "Visionite VCS-UM100";
-                       type_id = 730; /* CMOS sensor */
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else 
-               return -ENODEV; /* Not any of the know types; but the list keeps growing. */
-
-       memset(serial_number, 0, 30);
-       usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
-       Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
-
-       if (udev->descriptor.bNumConfigurations > 1)
-               Info("Warning: more than 1 configuration available.\n");
-
-       /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
-       pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
-       if (pdev == NULL) {
-               Err("Oops, could not allocate memory for pwc_device.\n");
-               return -ENOMEM;
-       }
-       pdev->type = type_id;
-       pdev->vsize = default_size;
-       pdev->vframes = default_fps;
-       strcpy(pdev->serial, serial_number);
-       pdev->features = features;
-       if (vendor_id == 0x046D && product_id == 0x08B5)
-       {
-               /* Logitech QuickCam Orbit
-                  The ranges have been determined experimentally; they may differ from cam to cam.
-                  Also, the exact ranges left-right and up-down are different for my cam
-                 */
-               pdev->angle_range.pan_min  = -7000;
-               pdev->angle_range.pan_max  =  7000;
-               pdev->angle_range.tilt_min = -3000;
-               pdev->angle_range.tilt_max =  2500;
-       }
-
-       init_MUTEX(&pdev->modlock);
-       spin_lock_init(&pdev->ptrlock);
-
-       pdev->udev = udev;
-       init_waitqueue_head(&pdev->frameq);
-       pdev->vcompression = pwc_preferred_compression;
-
-       /* Allocate video_device structure */
-       pdev->vdev = video_device_alloc();
-       if (pdev->vdev == 0)
-       {
-               Err("Err, cannot allocate video_device struture. Failing probe.");
-               kfree(pdev);
-               return -ENOMEM;
-       }
-       memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
-       strcpy(pdev->vdev->name, name);
-       pdev->vdev->owner = THIS_MODULE;
-       video_set_drvdata(pdev->vdev, pdev);
-
-       pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
-       Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
-
-       /* Now search device_hint[] table for a match, so we can hint a node number. */
-       for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
-               if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
-                    (device_hint[hint].pdev == NULL)) {
-                       /* so far, so good... try serial number */
-                       if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
-                               /* match! */
-                               video_nr = device_hint[hint].device_node;
-                               Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
-                               break;
-                       }
-               }
-       }
-
-       pdev->vdev->release = video_device_release;
-       i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
-       if (i < 0) {
-               Err("Failed to register as video device (%d).\n", i);
-               video_device_release(pdev->vdev); /* Drip... drip... drip... */
-               kfree(pdev); /* Oops, no memory leaks please */
-               return -EIO;
-       }
-       else {
-               Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
-       }
-
-       /* occupy slot */
-       if (hint < MAX_DEV_HINTS) 
-               device_hint[hint].pdev = pdev;
-
-       Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
-       usb_set_intfdata (intf, pdev);
-       return 0;
-}
-
-/* The user janked out the cable... */
-static void usb_pwc_disconnect(struct usb_interface *intf)
-{
-       struct pwc_device *pdev;
-       int hint;
-
-       lock_kernel();
-       pdev = usb_get_intfdata (intf);
-       usb_set_intfdata (intf, NULL);
-       if (pdev == NULL) {
-               Err("pwc_disconnect() Called without private pointer.\n");
-               goto disconnect_out;
-       }
-       if (pdev->udev == NULL) {
-               Err("pwc_disconnect() already called for %p\n", pdev);
-               goto disconnect_out;
-       }
-       if (pdev->udev != interface_to_usbdev(intf)) {
-               Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
-               goto disconnect_out;
-       }
-#ifdef PWC_MAGIC       
-       if (pdev->magic != PWC_MAGIC) {
-               Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
-               goto disconnect_out;
-       }
-#endif
-       
-       /* We got unplugged; this is signalled by an EPIPE error code */
-       if (pdev->vopen) {
-               Info("Disconnected while webcam is in use!\n");
-               pdev->error_status = EPIPE;
-       }
-
-       /* Alert waiting processes */
-       wake_up_interruptible(&pdev->frameq);
-       /* Wait until device is closed */
-       while (pdev->vopen)
-               schedule();
-       /* Device is now closed, so we can safely unregister it */
-       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
-       video_unregister_device(pdev->vdev);
-
-       /* Free memory (don't set pdev to 0 just yet) */
-       kfree(pdev);
-
-disconnect_out:
-       /* search device_hint[] table if we occupy a slot, by any chance */
-       for (hint = 0; hint < MAX_DEV_HINTS; hint++)
-               if (device_hint[hint].pdev == pdev)
-                       device_hint[hint].pdev = NULL;
-
-       unlock_kernel();
-}
-
-
-/* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(const char *s)
-{
-       int k = 0;
-
-       k = 0;
-       while (*s != '\0' && *s >= '0' && *s <= '9') {
-               k = 10 * k + (*s - '0');
-               s++;
-       }
-       return k;
-}
-
-
-/* 
- * Initialization code & module stuff 
- */
-
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
-static int compression = -1;
-static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
-
-module_param_string(size, size, sizeof(size), 0);
-MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
-MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
-MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
-MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
-MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
-MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
-MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
-MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
-MODULE_PARM_DESC(dev_hint, "Device node hints");
-
-MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
-MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
-MODULE_LICENSE("GPL");
-
-static int __init usb_pwc_init(void)
-{
-       int i, sz;
-       char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
-
-       Info("Philips webcam module version " PWC_VERSION " loaded.\n");
-       Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
-       Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
-       Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
-
-       if (fps) {
-               if (fps < 4 || fps > 30) {
-                       Err("Framerate out of bounds (4-30).\n");
-                       return -EINVAL;
-               }
-               default_fps = fps;
-               Info("Default framerate set to %d.\n", default_fps);
-       }
-
-       if (size[0]) {
-               /* string; try matching with array */
-               for (sz = 0; sz < PSZ_MAX; sz++) {
-                       if (!strcmp(sizenames[sz], size)) { /* Found! */
-                               default_size = sz;
-                               break;
-                       }
-               }
-               if (sz == PSZ_MAX) {
-                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
-                       return -EINVAL;
-               }
-               Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
-       }
-       if (mbufs) {
-               if (mbufs < 1 || mbufs > MAX_IMAGES) {
-                       Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
-                       return -EINVAL;
-               }
-               default_mbufs = mbufs;
-               Info("Number of image buffers set to %d.\n", default_mbufs);
-       }
-       if (fbufs) {
-               if (fbufs < 2 || fbufs > MAX_FRAMES) {
-                       Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
-                       return -EINVAL;
-               }
-               default_fbufs = fbufs;
-               Info("Number of frame buffers set to %d.\n", default_fbufs);
-       }
-       if (trace >= 0) {
-               Info("Trace options: 0x%04x\n", trace);
-               pwc_trace = trace;
-       }
-       if (compression >= 0) {
-               if (compression > 3) {
-                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
-                       return -EINVAL;
-               }
-               pwc_preferred_compression = compression;
-               Info("Preferred compression set to %d.\n", pwc_preferred_compression);
-       }
-       if (power_save)
-               Info("Enabling power save on open/close.\n");
-       if (leds[0] >= 0)
-               led_on = leds[0];
-       if (leds[1] >= 0)
-               led_off = leds[1];
-
-       /* Big device node whoopla. Basically, it allows you to assign a
-          device node (/dev/videoX) to a camera, based on its type
-          & serial number. The format is [type[.serialnumber]:]node.
-
-          Any camera that isn't matched by these rules gets the next
-          available free device node.
-        */
-       for (i = 0; i < MAX_DEV_HINTS; i++) {
-               char *s, *colon, *dot;
-
-               /* This loop also initializes the array */
-               device_hint[i].pdev = NULL;
-               s = dev_hint[i];
-               if (s != NULL && *s != '\0') {
-                       device_hint[i].type = -1; /* wildcard */
-                       strcpy(device_hint[i].serial_number, "*");
-
-                       /* parse string: chop at ':' & '/' */
-                       colon = dot = s;
-                       while (*colon != '\0' && *colon != ':')
-                               colon++;
-                       while (*dot != '\0' && *dot != '.')
-                               dot++;
-                       /* Few sanity checks */
-                       if (*dot != '\0' && dot > colon) {
-                               Err("Malformed camera hint: the colon must be after the dot.\n");
-                               return -EINVAL;
-                       }
-
-                       if (*colon == '\0') {
-                               /* No colon */
-                               if (*dot != '\0') {
-                                       Err("Malformed camera hint: no colon + device node given.\n");
-                                       return -EINVAL;
-                               }
-                               else {
-                                       /* No type or serial number specified, just a number. */
-                                       device_hint[i].device_node = pwc_atoi(s);
-                               }
-                       }
-                       else {
-                               /* There's a colon, so we have at least a type and a device node */
-                               device_hint[i].type = pwc_atoi(s);
-                               device_hint[i].device_node = pwc_atoi(colon + 1);
-                               if (*dot != '\0') {
-                                       /* There's a serial number as well */
-                                       int k;
-                                       
-                                       dot++;
-                                       k = 0;
-                                       while (*dot != ':' && k < 29) {
-                                               device_hint[i].serial_number[k++] = *dot;
-                                               dot++;
-                                       }
-                                       device_hint[i].serial_number[k] = '\0';
-                               }
-                       }
-#if PWC_DEBUG          
-                       Debug("device_hint[%d]:\n", i);
-                       Debug("  type    : %d\n", device_hint[i].type);
-                       Debug("  serial# : %s\n", device_hint[i].serial_number);
-                       Debug("  node    : %d\n", device_hint[i].device_node);
-#endif                 
-               }
-               else
-                       device_hint[i].type = 0; /* not filled */
-       } /* ..for MAX_DEV_HINTS */
-
-       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
-       return usb_register(&pwc_driver);
-}
-
-static void __exit usb_pwc_exit(void)
-{
-       Trace(TRACE_MODULE, "Deregistering driver.\n");
-       usb_deregister(&pwc_driver);
-       Info("Philips webcam module removed.\n");
-}
-
-module_init(usb_pwc_init);
-module_exit(usb_pwc_exit);
-
diff --git a/drivers/usb/media/pwc/pwc-ioctl.h b/drivers/usb/media/pwc/pwc-ioctl.h
deleted file mode 100644 (file)
index 5f9cb08..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-#ifndef PWC_IOCTL_H
-#define PWC_IOCTL_H
-
-/* (C) 2001-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* This is pwc-ioctl.h belonging to PWC 8.12.1
-   It contains structures and defines to communicate from user space
-   directly to the driver.
- */
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added ioctl constants to access methods for
-                          changing white balance and red/blue gains
-   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
-   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
-               PWCX easier
- */
-
-/* These are private ioctl() commands, specific for the Philips webcams.
-   They contain functions not found in other webcams, and settings not
-   specified in the Video4Linux API.
-
-   The #define names are built up like follows:
-   VIDIOC              VIDeo IOCtl prefix
-         PWC           Philps WebCam
-            G           optional: Get
-            S           optional: Set
-             ...       the function
- */
-
-
- /* Enumeration of image sizes */
-#define PSZ_SQCIF      0x00
-#define PSZ_QSIF       0x01
-#define PSZ_QCIF       0x02
-#define PSZ_SIF                0x03
-#define PSZ_CIF                0x04
-#define PSZ_VGA                0x05
-#define PSZ_MAX                6
-
-
-/* The frame rate is encoded in the video_window.flags parameter using
-   the upper 16 bits, since some flags are defined nowadays. The following
-   defines provide a mask and shift to filter out this value.
-
-   In 'Snapshot' mode the camera freezes its automatic exposure and colour
-   balance controls.
- */
-#define PWC_FPS_SHIFT          16
-#define PWC_FPS_MASK           0x00FF0000
-#define PWC_FPS_FRMASK         0x003F0000
-#define PWC_FPS_SNAPSHOT       0x00400000
-
-
-/* structure for transferring x & y coordinates */
-struct pwc_coord
-{
-       int x, y;               /* guess what */
-       int size;               /* size, or offset */
-};
-
-
-/* Used with VIDIOCPWCPROBE */
-struct pwc_probe
-{
-       char name[32];
-       int type;
-};
-
-struct pwc_serial
-{
-       char serial[30];        /* String with serial number. Contains terminating 0 */
-};
-       
-/* pwc_whitebalance.mode values */
-#define PWC_WB_INDOOR          0
-#define PWC_WB_OUTDOOR         1
-#define PWC_WB_FL              2
-#define PWC_WB_MANUAL          3
-#define PWC_WB_AUTO            4
-
-/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). 
-   Set mode to one of the PWC_WB_* values above.
-   *red and *blue are the respective gains of these colour components inside 
-   the camera; range 0..65535
-   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
-   otherwise undefined.
-   'read_red' and 'read_blue' are read-only.
-*/   
-struct pwc_whitebalance
-{
-       int mode;
-       int manual_red, manual_blue;    /* R/W */
-       int read_red, read_blue;        /* R/O */
-};
-
-/* 
-   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
-   and tell the camera how fast it should react to changes in lighting, and 
-   with how much delay. Valid values are 0..65535.
-*/
-struct pwc_wb_speed
-{
-       int control_speed;
-       int control_delay;
-
-};
-
-/* Used with VIDIOCPWC[SG]LED */
-struct pwc_leds
-{
-       int led_on;                     /* Led on-time; range = 0..25000 */
-       int led_off;                    /* Led off-time; range = 0..25000  */
-};
-
-/* Image size (used with GREALSIZE) */
-struct pwc_imagesize
-{
-       int width;
-       int height;
-};
-
-/* Defines and structures for Motorized Pan & Tilt */
-#define PWC_MPT_PAN            0x01
-#define PWC_MPT_TILT           0x02
-#define PWC_MPT_TIMEOUT                0x04 /* for status */
-
-/* Set angles; when absolute != 0, the angle is absolute and the 
-   driver calculates the relative offset for you. This can only
-   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
-   absolute angles.
- */   
-struct pwc_mpt_angles
-{
-       int absolute;           /* write-only */
-       int pan;                /* degrees * 100 */
-       int tilt;               /* degress * 100 */
-};
-
-/* Range of angles of the camera, both horizontally and vertically.
- */
-struct pwc_mpt_range
-{
-       int pan_min, pan_max;           /* degrees * 100 */
-       int tilt_min, tilt_max;
-};
-
-struct pwc_mpt_status
-{
-       int status;
-       int time_pan;
-       int time_tilt;
-};
-
-
-/* This is used for out-of-kernel decompression. With it, you can get
-   all the necessary information to initialize and use the decompressor
-   routines in standalone applications.
- */   
-struct pwc_video_command
-{
-       int type;               /* camera type (645, 675, 730, etc.) */
-       int release;            /* release number */
-
-        int size;              /* one of PSZ_* */
-        int alternate;
-       int command_len;        /* length of USB video command */
-       unsigned char command_buf[13];  /* Actual USB video command */
-       int bandlength;         /* >0 = compressed */
-       int frame_size;         /* Size of one (un)compressed frame */
-};
-
-/* Flags for PWCX subroutines. Not all modules honour all flags. */
-#define PWCX_FLAG_PLANAR       0x0001
-#define PWCX_FLAG_BAYER                0x0008
-
-
-/* IOCTL definitions */
-
- /* Restore user settings */
-#define VIDIOCPWCRUSER         _IO('v', 192)
- /* Save user settings */
-#define VIDIOCPWCSUSER         _IO('v', 193)
- /* Restore factory settings */
-#define VIDIOCPWCFACTORY       _IO('v', 194)
-
- /* You can manipulate the compression factor. A compression preference of 0
-    means use uncompressed modes when available; 1 is low compression, 2 is
-    medium and 3 is high compression preferred. Of course, the higher the
-    compression, the lower the bandwidth used but more chance of artefacts
-    in the image. The driver automatically chooses a higher compression when
-    the preferred mode is not available.
-  */
- /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
-#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
- /* Get preferred compression quality */
-#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
-
-
-/* Retrieve serial number of camera */
-#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
-
- /* This is a probe function; since so many devices are supported, it
-    becomes difficult to include all the names in programs that want to
-    check for the enhanced Philips stuff. So in stead, try this PROBE;
-    it returns a structure with the original name, and the corresponding
-    Philips type.
-    To use, fill the structure with zeroes, call PROBE and if that succeeds,
-    compare the name with that returned from VIDIOCGCAP; they should be the
-    same. If so, you can be assured it is a Philips (OEM) cam and the type
-    is valid.
- */
-#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
-
- /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
-#define VIDIOCPWCSAGC          _IOW('v', 200, int)
- /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCGAGC          _IOR('v', 200, int)
- /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
-
- /* Color compensation (Auto White Balance) */
-#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
-#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
-
- /* Auto WB speed */
-#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
-#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
-
- /* LEDs on/off/blink; int range 0..65535 */
-#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
-#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
-
-  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
-#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
-#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
-
-  /* Backlight compensation; 0 = off, otherwise on */
-#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
-#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
-
-  /* Flickerless mode; = 0 off, otherwise on */
-#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
-#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)  
-
-  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
-#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
-#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
-
- /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
-#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
-
- /* Motorized pan & tilt functions */ 
-#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
-#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
-#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
-
- /* Get the USB set-video command; needed for initializing libpwcx */
-#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
-struct pwc_table_init_buffer {
-   int len;
-   char *buffer;
-
-};
-#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
-
-#endif
diff --git a/drivers/usb/media/pwc/pwc-kiara.c b/drivers/usb/media/pwc/pwc-kiara.c
deleted file mode 100644 (file)
index c498c68..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-/* This tables contains entries for the 730/740/750 (Kiara) camera, with
-   4 different qualities (no compression, low, medium, high).
-   It lists the bandwidth requirements for said mode by its alternate interface
-   number. An alternate of 0 means that the mode is unavailable.
-
-   There are 6 * 4 * 4 entries:
-     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
-     6 framerates: 5, 10, 15, 20, 25, 30
-     4 compression modi: none, low, medium, high
-
-   When an uncompressed mode is not available, the next available compressed mode
-   will be chosen (unless the decompressor is absent). Sometimes there are only
-   1 or 2 compressed modes available; in that case entries are duplicated.
-*/
-
-
-#include "pwc-kiara.h"
-#include "pwc-uncompress.h"
-
-const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
-{
-   /* SQCIF */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-   /* QSIF */
-   {
-      /* 5 fps */
-      {
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-      },
-      /* 10 fps */
-      {
-         {2, 291,    0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}},
-         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
-         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
-         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
-      },
-      /* 15 fps */
-      {
-         {3, 437,    0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}},
-         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
-         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
-         {1, 192,  420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
-      },
-      /* 20 fps */
-      {
-         {4, 589,    0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}},
-         {3, 448,  730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}},
-         {2, 292,  476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}},
-         {1, 192,  312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
-      },
-      /* 25 fps */
-      {
-         {5, 703,    0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}},
-         {3, 447,  610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}},
-         {2, 292,  398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}},
-         {1, 193,  262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}},
-      },
-      /* 30 fps */
-      {
-         {8, 874,    0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}},
-         {5, 704,  730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}},
-         {3, 448,  492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}},
-         {2, 292,  320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}},
-      },
-   },
-   /* QCIF */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-   /* SIF */
-   {
-      /* 5 fps */
-      {
-         {4, 582,    0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}},
-         {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}},
-         {2, 291,  960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}},
-         {1, 191,  630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}},
-         {3, 447,  736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}},
-         {2, 292,  480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}},
-         {4, 592,  650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}},
-         {3, 448,  492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {9, 958,  782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}},
-         {5, 703,  574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}},
-         {3, 446,  364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}},
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {9, 958,  654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}},
-         {6, 776,  530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}},
-         {4, 592,  404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}},
-         {6, 775,  426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}},
-         {4, 590,  324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}},
-      },
-   },
-   /* CIF */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-   /* VGA */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}},
-         {4, 592,  976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}},
-         {3, 448,  738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {9, 956,  788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}},
-         {6, 776,  640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}},
-         {4, 592,  488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
-         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
-         {8, 895,  492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-};
-
diff --git a/drivers/usb/media/pwc/pwc-kiara.h b/drivers/usb/media/pwc/pwc-kiara.h
deleted file mode 100644 (file)
index 12929ab..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* Entries for the Kiara (730/740/750) camera */
-
-#ifndef PWC_KIARA_H
-#define PWC_KIARA_H
-
-#include "pwc-ioctl.h"
-
-struct Kiara_table_entry
-{
-       char alternate;                 /* USB alternate interface */
-       unsigned short packetsize;      /* Normal packet size */
-       unsigned short bandlength;      /* Bandlength when decompressing */
-       unsigned char mode[12];         /* precomputed mode settings for cam */
-};
-
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
-
-#endif
-
-
diff --git a/drivers/usb/media/pwc/pwc-misc.c b/drivers/usb/media/pwc/pwc-misc.c
deleted file mode 100644 (file)
index b7a4bd3..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Linux driver for Philips webcam 
-   Various miscellaneous functions and tables.
-   (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/slab.h>
-
-#include "pwc.h"
-
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
-{
-       { 128,  96, 0 },
-       { 160, 120, 0 },
-       { 176, 144, 0 },
-       { 320, 240, 0 },
-       { 352, 288, 0 },
-       { 640, 480, 0 },
-};
-
-/* x,y -> PSZ_ */
-int pwc_decode_size(struct pwc_device *pdev, int width, int height)
-{
-       int i, find;
-
-       /* Make sure we don't go beyond our max size.
-           NB: we have different limits for RAW and normal modes. In case
-           you don't have the decompressor loaded or use RAW mode, 
-           the maximum viewable size is smaller.
-        */
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
-       {
-               if (width > pdev->abs_max.x || height > pdev->abs_max.y)
-               {
-                       Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
-                       return -1;
-                }
-       }
-       else
-       {
-               if (width > pdev->view_max.x || height > pdev->view_max.y)
-               {
-                       Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
-                       return -1;
-               }
-       }
-
-       /* Find the largest size supported by the camera that fits into the
-          requested size.
-        */
-       find = -1;
-       for (i = 0; i < PSZ_MAX; i++) {
-               if (pdev->image_mask & (1 << i)) {
-                       if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
-                               find = i;
-               }
-       }
-       return find;
-}
-
-/* initialize variables depending on type and decompressor*/
-void pwc_construct(struct pwc_device *pdev)
-{
-       switch(pdev->type) {
-       case 645:
-       case 646:
-               pdev->view_min.x = 128;
-               pdev->view_min.y =  96;
-               pdev->view_max.x = 352;
-               pdev->view_max.y = 288;
-                pdev->abs_max.x  = 352;
-                pdev->abs_max.y  = 288;
-               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
-               pdev->vcinterface = 2;
-               pdev->vendpoint = 4;
-               pdev->frame_header_size = 0;
-               pdev->frame_trailer_size = 0;
-               break;
-       case 675:
-       case 680:
-       case 690:
-               pdev->view_min.x = 128;
-               pdev->view_min.y =  96;
-               /* Anthill bug #38: PWC always reports max size, even without PWCX */
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
-               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
-                pdev->abs_max.x = 640;
-                pdev->abs_max.y = 480;
-               pdev->vcinterface = 3;
-               pdev->vendpoint = 4;
-               pdev->frame_header_size = 0;
-               pdev->frame_trailer_size = 0;
-               break;
-       case 720:
-       case 730:
-       case 740:
-       case 750:
-               pdev->view_min.x = 160;
-               pdev->view_min.y = 120;
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
-               pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
-                pdev->abs_max.x = 640;
-                pdev->abs_max.y = 480;
-               pdev->vcinterface = 3;
-               pdev->vendpoint = 5;
-               pdev->frame_header_size = TOUCAM_HEADER_SIZE;
-               pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
-               break;
-       }
-       Debug("type = %d\n",pdev->type);
-       pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
-       pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
-       pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
-       /* length of image, in YUV format; always allocate enough memory. */
-       pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
-}
-
-
diff --git a/drivers/usb/media/pwc/pwc-nala.h b/drivers/usb/media/pwc/pwc-nala.h
deleted file mode 100644 (file)
index e6c5cb6..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-   /* SQCIF */
-   {
-      {0, 0, {0x04, 0x01, 0x03}},
-      {8, 0, {0x05, 0x01, 0x03}},
-      {7, 0, {0x08, 0x01, 0x03}},
-      {7, 0, {0x0A, 0x01, 0x03}},
-      {6, 0, {0x0C, 0x01, 0x03}},
-      {5, 0, {0x0F, 0x01, 0x03}},
-      {4, 0, {0x14, 0x01, 0x03}},
-      {3, 0, {0x18, 0x01, 0x03}},
-   },
-   /* QSIF */
-   {
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-   },
-   /* QCIF */
-   {
-      {0, 0, {0x04, 0x01, 0x02}},
-      {8, 0, {0x05, 0x01, 0x02}},
-      {7, 0, {0x08, 0x01, 0x02}},
-      {6, 0, {0x0A, 0x01, 0x02}},
-      {5, 0, {0x0C, 0x01, 0x02}},
-      {4, 0, {0x0F, 0x01, 0x02}},
-      {1, 0, {0x14, 0x01, 0x02}},
-      {1, 0, {0x18, 0x01, 0x02}},
-   },
-   /* SIF */
-   {
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-   },
-   /* CIF */
-   {
-      {4, 0, {0x04, 0x01, 0x01}},
-      {7, 1, {0x05, 0x03, 0x01}},
-      {6, 1, {0x08, 0x03, 0x01}},
-      {4, 1, {0x0A, 0x03, 0x01}},
-      {3, 1, {0x0C, 0x03, 0x01}},
-      {2, 1, {0x0F, 0x03, 0x01}},
-      {0},
-      {0},
-   },
-   /* VGA */
-   {  
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-   },
diff --git a/drivers/usb/media/pwc/pwc-timon.c b/drivers/usb/media/pwc/pwc-timon.c
deleted file mode 100644 (file)
index dee9671..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-/* This tables contains entries for the 675/680/690 (Timon) camera, with
-   4 different qualities (no compression, low, medium, high).
-   It lists the bandwidth requirements for said mode by its alternate interface
-   number. An alternate of 0 means that the mode is unavailable.
-
-   There are 6 * 4 * 4 entries:
-     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
-     6 framerates: 5, 10, 15, 20, 25, 30
-     4 compression modi: none, low, medium, high
-
-   When an uncompressed mode is not available, the next available compressed mode
-   will be chosen (unless the decompressor is absent). Sometimes there are only
-   1 or 2 compressed modes available; in that case entries are duplicated.
-*/
-
-#include "pwc-timon.h"
-
-const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
-{
-   /* SQCIF */
-   {
-      /* 5 fps */
-      {
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-      },
-   },
-   /* QSIF */
-   {
-      /* 5 fps */
-      {
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {2, 291,    0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}},
-         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {3, 437,    0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}},
-         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {1, 191,  420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {4, 588,    0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}},
-         {3, 447,  730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
-         {1, 192,  312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {5, 703,    0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}},
-         {3, 447,  610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
-         {1, 192,  262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {8, 873,    0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}},
-         {5, 704,  774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}},
-         {3, 448,  492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}},
-         {2, 291,  320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
-      },
-   },
-   /* QCIF */
-   {
-      /* 5 fps */
-      {
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {3, 385,    0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}},
-         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {1, 194,  532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {4, 577,    0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}},
-         {3, 447,  818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}},
-         {1, 195,  356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {6, 776,    0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}},
-         {4, 591,  804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}},
-         {3, 447,  608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 291,  396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {9, 928,    0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}},
-         {5, 703,  800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}},
-         {3, 447,  508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 956,  876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}},
-         {4, 592,  542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}},
-         {2, 291,  266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}},
-      },
-   },
-   /* SIF */
-   {
-      /* 5 fps */
-      {
-         {4, 582,    0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}},
-         {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}},
-         {2, 291,  960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}},
-         {1, 191,  630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}},
-         {3, 447,  736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}},
-         {2, 291,  480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}},
-         {4, 591,  650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}},
-         {3, 448,  492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {9, 958,  782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}},
-         {5, 703,  574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}},
-         {3, 446,  364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {9, 958,  654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}},
-         {6, 776,  530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}},
-         {4, 592,  404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}},
-         {6, 775,  426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}},
-         {4, 590,  324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}},
-      },
-   },
-   /* CIF */
-   {
-      /* 5 fps */
-      {
-         {6, 771,    0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}},
-         {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}},
-         {2, 291,  800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}},
-         {1, 193,  528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}},
-         {4, 591,  812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}},
-         {2, 291,  400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 956,  876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}},
-         {5, 703,  644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}},
-         {3, 448,  410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {9, 956,  650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}},
-         {6, 776,  528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}},
-         {4, 591,  402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}},
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {9, 956,  544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}},
-         {7, 840,  478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}},
-         {5, 703,  400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 956,  438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}},
-         {7, 838,  384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}},
-         {6, 773,  354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}},
-      },
-   },
-   /* VGA */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}},
-         {4, 592,  976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}},
-         {3, 448,  738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {9, 956,  788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}},
-         {6, 776,  640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}},
-         {4, 592,  488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
-         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
-         {8, 895,  492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-};
-
diff --git a/drivers/usb/media/pwc/pwc-timon.h b/drivers/usb/media/pwc/pwc-timon.h
deleted file mode 100644 (file)
index a86b378..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-
-/* This tables contains entries for the 675/680/690 (Timon) camera, with
-   4 different qualities (no compression, low, medium, high).
-   It lists the bandwidth requirements for said mode by its alternate interface
-   number. An alternate of 0 means that the mode is unavailable.
-
-   There are 6 * 4 * 4 entries:
-     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
-     6 framerates: 5, 10, 15, 20, 25, 30
-     4 compression modi: none, low, medium, high
-
-   When an uncompressed mode is not available, the next available compressed mode
-   will be chosen (unless the decompressor is absent). Sometimes there are only
-   1 or 2 compressed modes available; in that case entries are duplicated.
-*/
-
-#ifndef PWC_TIMON_H
-#define PWC_TIMON_H
-
-#include "pwc-ioctl.h"
-
-struct Timon_table_entry
-{
-       char alternate;                 /* USB alternate interface */
-       unsigned short packetsize;      /* Normal packet size */
-       unsigned short bandlength;      /* Bandlength when decompressing */
-       unsigned char mode[13];         /* precomputed mode settings for cam */
-};
-
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
-
-
-#endif
-
-
diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c
deleted file mode 100644 (file)
index ef4204e..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Linux driver for Philips webcam
-   Decompression frontend.
-   (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <asm/current.h>
-#include <asm/types.h>
-
-#include "pwc.h"
-#include "pwc-uncompress.h"
-
-int pwc_decompress(struct pwc_device *pdev)
-{
-       struct pwc_frame_buf *fbuf;
-       int n, line, col, stride;
-       void *yuv, *image;
-       u16 *src;
-       u16 *dsty, *dstu, *dstv;
-
-       if (pdev == NULL)
-               return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
-       if (pdev->magic != PWC_MAGIC) {
-               Err("pwc_decompress(): magic failed.\n");
-               return -EFAULT;
-       }
-#endif
-
-       fbuf = pdev->read_frame;
-       if (fbuf == NULL)
-               return -EFAULT;
-       image = pdev->image_ptr[pdev->fill_image];
-       if (!image)
-               return -EFAULT;
-
-       yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
-
-       /* Raw format; that's easy... */
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
-       {
-               memcpy(image, yuv, pdev->frame_size);
-               return 0;
-       }
-
-       if (pdev->vbandlength == 0) {
-               /* Uncompressed mode. We copy the data into the output buffer,
-                  using the viewport size (which may be larger than the image
-                  size). Unfortunately we have to do a bit of byte stuffing
-                  to get the desired output format/size.
-                */
-                       /*
-                        * We do some byte shuffling here to go from the
-                        * native format to YUV420P.
-                        */
-                       src = (u16 *)yuv;
-                       n = pdev->view.x * pdev->view.y;
-
-                       /* offset in Y plane */
-                       stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
-                       dsty = (u16 *)(image + stride);
-
-                       /* offsets in U/V planes */
-                       stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
-                       dstu = (u16 *)(image + n +         stride);
-                       dstv = (u16 *)(image + n + n / 4 + stride);
-
-                       /* increment after each line */
-                       stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
-                       for (line = 0; line < pdev->image.y; line++) {
-                               for (col = 0; col < pdev->image.x; col += 4) {
-                                       *dsty++ = *src++;
-                                       *dsty++ = *src++;
-                                       if (line & 1)
-                                               *dstv++ = *src++;
-                                       else
-                                               *dstu++ = *src++;
-                               }
-                               dsty += stride;
-                               if (line & 1)
-                                       dstv += (stride >> 1);
-                               else
-                                       dstu += (stride >> 1);
-                       }
-       }
-       else {
-               /* Compressed; the decompressor routines will write the data
-                  in planar format immediately.
-                */
-               int flags;
-                
-                flags = PWCX_FLAG_PLANAR;
-                if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
-                {
-                  printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
-                  flags |= PWCX_FLAG_BAYER;
-                  return -ENXIO; /* No such device or address: missing decompressor */
-                }
-
-#if 0
-               switch (pdev->type)
-                {
-                 case 675:
-                 case 680:
-                 case 690:
-                 case 720:
-                 case 730:
-                 case 740:
-                 case 750:
-                   pwc_dec23_decompress(&pdev->image, &pdev->view,
-                               &pdev->offset, yuv, image, flags,
-                               pdev->decompress_data, pdev->vbandlength);
-                   break;
-                 case 645:
-                 case 646:
-                   /* TODO & FIXME */
-                   return -ENXIO; /* Missing decompressor */
-                   break;
-                }
-#endif
-       }
-       return 0;
-}
-
-
diff --git a/drivers/usb/media/pwc/pwc-uncompress.h b/drivers/usb/media/pwc/pwc-uncompress.h
deleted file mode 100644 (file)
index d3b9250..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* This file is the bridge between the kernel module and the plugin; it
-   describes the structures and datatypes used in both modules. Any
-   significant change should be reflected by increasing the 
-   pwc_decompressor_version major number.
- */
-#ifndef PWC_UNCOMPRESS_H
-#define PWC_UNCOMPRESS_H
-
-#include <linux/config.h>
-
-#include "pwc-ioctl.h"
-
-/* from pwc-dec.h */
-#define PWCX_FLAG_PLANAR        0x0001
-/* */
-
-#endif
diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h
deleted file mode 100644 (file)
index 6dd76bb..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#ifndef PWC_H
-#define PWC_H
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/spinlock.h>
-#include <linux/videodev.h>
-#include <linux/wait.h>
-#include <linux/smp_lock.h>
-#include <asm/semaphore.h>
-#include <asm/errno.h>
-
-#include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
-
-/* Turn some debugging options on/off */
-#define PWC_DEBUG 0
-
-/* Trace certain actions in the driver */
-#define TRACE_MODULE   0x0001
-#define TRACE_PROBE    0x0002
-#define TRACE_OPEN     0x0004
-#define TRACE_READ     0x0008
-#define TRACE_MEMORY   0x0010
-#define TRACE_FLOW     0x0020
-#define TRACE_SIZE     0x0040
-#define TRACE_PWCX     0x0080
-#define TRACE_SEQUENCE 0x1000
-
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
-#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
-
-
-/* Defines for ToUCam cameras */
-#define TOUCAM_HEADER_SIZE             8
-#define TOUCAM_TRAILER_SIZE            4
-
-#define FEATURE_MOTOR_PANTILT          0x0001
-
-/* Version block */
-#define PWC_MAJOR      9
-#define PWC_MINOR      0
-#define PWC_VERSION    "9.0.2-unofficial"
-#define PWC_NAME       "pwc"
-
-/* Turn certain features on/off */
-#define PWC_INT_PIPE 0
-
-/* Ignore errors in the first N frames, to allow for startup delays */
-#define FRAME_LOWMARK 5
-
-/* Size and number of buffers for the ISO pipe. */
-#define MAX_ISO_BUFS           2
-#define ISO_FRAMES_PER_DESC    10
-#define ISO_MAX_FRAME_SIZE     960
-#define ISO_BUFFER_SIZE        (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
-
-/* Frame buffers: contains compressed or uncompressed video data. */
-#define MAX_FRAMES             5
-/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
-#define PWC_FRAME_SIZE                 (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
-
-/* Absolute maximum number of buffers available for mmap() */
-#define MAX_IMAGES             10
-
-/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
-struct pwc_iso_buf
-{
-       void *data;
-       int  length;
-       int  read;
-       struct urb *urb;
-};
-
-/* intermediate buffers with raw data from the USB cam */
-struct pwc_frame_buf
-{
-   void *data;
-   volatile int filled;                /* number of bytes filled */
-   struct pwc_frame_buf *next; /* list */
-#if PWC_DEBUG
-   int sequence;               /* Sequence number */
-#endif
-};
-
-struct pwc_device
-{
-   struct video_device *vdev;
-#ifdef PWC_MAGIC
-   int magic;
-#endif
-   /* Pointer to our usb_device */
-   struct usb_device *udev;
-   
-   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
-   int release;                        /* release number */
-   int features;               /* feature bits */
-   char serial[30];            /* serial number (string) */
-   int error_status;           /* set when something goes wrong with the cam (unplugged, USB errors) */
-   int usb_init;               /* set when the cam has been initialized over USB */
-
-   /*** Video data ***/
-   int vopen;                  /* flag */
-   int vendpoint;              /* video isoc endpoint */
-   int vcinterface;            /* video control interface */
-   int valternate;             /* alternate interface needed */
-   int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
-   int vpalette;               /* palette: 420P, RAW or RGBBAYER */
-   int vframe_count;           /* received frames */
-   int vframes_dumped;                 /* counter for dumped frames */
-   int vframes_error;          /* frames received in error */
-   int vmax_packet_size;       /* USB maxpacket size */
-   int vlast_packet_size;      /* for frame synchronisation */
-   int visoc_errors;           /* number of contiguous ISOC errors */
-   int vcompression;           /* desired compression factor */
-   int vbandlength;            /* compressed band length; 0 is uncompressed */
-   char vsnapshot;             /* snapshot mode */
-   char vsync;                 /* used by isoc handler */
-   char vmirror;               /* for ToUCaM series */
-   
-   int cmd_len;
-   unsigned char cmd_buf[13];
-
-   /* The image acquisition requires 3 to 4 steps:
-      1. data is gathered in short packets from the USB controller
-      2. data is synchronized and packed into a frame buffer
-      3a. in case data is compressed, decompress it directly into image buffer
-      3b. in case data is uncompressed, copy into image buffer with viewport
-      4. data is transferred to the user process
-
-      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
-      We have in effect a back-to-back-double-buffer system.
-    */
-   /* 1: isoc */
-   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
-   char iso_init;
-
-   /* 2: frame */
-   struct pwc_frame_buf *fbuf; /* all frames */
-   struct pwc_frame_buf *empty_frames, *empty_frames_tail;     /* all empty frames */
-   struct pwc_frame_buf *full_frames, *full_frames_tail;       /* all filled frames */
-   struct pwc_frame_buf *fill_frame;   /* frame currently being filled */
-   struct pwc_frame_buf *read_frame;   /* frame currently read by user process */
-   int frame_header_size, frame_trailer_size;
-   int frame_size;
-   int frame_total_size; /* including header & trailer */
-   int drop_frames;
-#if PWC_DEBUG
-   int sequence;                       /* Debugging aid */
-#endif
-
-   /* 3: decompression */
-   struct pwc_decompressor *decompressor;      /* function block with decompression routines */
-   void *decompress_data;              /* private data for decompression engine */
-
-   /* 4: image */
-   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
-      as delivered by the camera, and 'view' is the size requested by the
-      program. The camera image is centered in this viewport, laced with
-      a gray or black border. view_min <= image <= view <= view_max;
-    */
-   int image_mask;                     /* bitmask of supported sizes */
-   struct pwc_coord view_min, view_max;        /* minimum and maximum viewable sizes */
-   struct pwc_coord abs_max;            /* maximum supported size with compression */
-   struct pwc_coord image, view;       /* image and viewport size */
-   struct pwc_coord offset;            /* offset within the viewport */
-
-   void *image_data;                   /* total buffer, which is subdivided into ... */
-   void *image_ptr[MAX_IMAGES];                /* ...several images... */
-   int fill_image;                     /* ...which are rotated. */
-   int len_per_image;                  /* length per image */
-   int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
-   int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
-
-   struct semaphore modlock;           /* to prevent races in video_open(), etc */
-   spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
-
-   /*** motorized pan/tilt feature */
-   struct pwc_mpt_range angle_range;
-   int pan_angle;                      /* in degrees * 100 */
-   int tilt_angle;                     /* absolute angle; 0,0 is home position */
-
-   /*** Misc. data ***/
-   wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
-#if PWC_INT_PIPE
-   void *usb_int_handler;              /* for the interrupt endpoint */
-#endif
-};
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Global variable */
-extern int pwc_trace;
-
-/** functions in pwc-if.c */
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
-
-/** Functions in pwc-misc.c */
-/* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
-
-int pwc_decode_size(struct pwc_device *pdev, int width, int height);
-void pwc_construct(struct pwc_device *pdev);
-
-/** Functions in pwc-ctrl.c */
-/* Request a certain video mode. Returns < 0 if not possible */
-extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
-
-/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
-extern int pwc_get_brightness(struct pwc_device *pdev);
-extern int pwc_set_brightness(struct pwc_device *pdev, int value);
-extern int pwc_get_contrast(struct pwc_device *pdev);
-extern int pwc_set_contrast(struct pwc_device *pdev, int value);
-extern int pwc_get_gamma(struct pwc_device *pdev);
-extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
-extern int pwc_set_saturation(struct pwc_device *pdev, int value);
-extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
-extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
-
-/* Power down or up the camera; not supported by all models */
-extern int pwc_camera_power(struct pwc_device *pdev, int power);
-
-/* Private ioctl()s; see pwc-ioctl.h */
-extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
-
-
-/** pwc-uncompress.c */
-/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
-extern int pwc_decompress(struct pwc_device *pdev);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
deleted file mode 100644 (file)
index f03ea7f..0000000
+++ /dev/null
@@ -1,1435 +0,0 @@
-/*
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- *
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
- * their chipset available and supporting me while writing this driver.
- *     - Jeroen Vreeken
- */
-
-static const char version[] = "0.24";
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/usb.h>
-#include "se401.h"
-
-static int flickerless=0;
-static int video_nr = -1;
-
-static struct usb_device_id device_table [] = {
-       { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
-       { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
-       { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
-       { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
-       { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, device_table);
-
-MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
-MODULE_DESCRIPTION("SE401 USB Camera Driver");
-MODULE_LICENSE("GPL");
-module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
-module_param(video_nr, int, 0);
-
-static struct usb_driver se401_driver;
-
-
-/**********************************************************************
- *
- * Memory management
- *
- **********************************************************************/
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-
-
-/****************************************************************************
- *
- * se401 register read/write functions
- *
- ***************************************************************************/
-
-static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
-                        unsigned short value, unsigned char *cp, int size)
-{
-       return usb_control_msg (
-                se401->dev,
-                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
-                req,
-                (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                value,
-                0,
-                cp,
-                size,
-                1000
-        );
-}
-
-static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
-                            unsigned short param)
-{
-       /* specs say that the selector (address) should go in the value field
-          and the param in index, but in the logs of the windows driver they do
-          this the other way around...
-        */
-       return usb_control_msg (
-               se401->dev,
-               usb_sndctrlpipe(se401->dev, 0),
-               SE401_REQ_SET_EXT_FEATURE,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               param,
-               selector,
-                NULL,
-                0,
-                1000
-        );
-}
-
-static unsigned short se401_get_feature(struct usb_se401 *se401, 
-                                       unsigned short selector)
-{
-       /* For 'set' the selecetor should be in index, not sure if the spec is
-          wrong here to....
-        */
-       unsigned char cp[2];
-        usb_control_msg (
-                se401->dev,
-                usb_rcvctrlpipe(se401->dev, 0),
-                SE401_REQ_GET_EXT_FEATURE,
-                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0,
-                selector,
-                cp,
-                2,
-                1000
-        );
-       return cp[0]+cp[1]*256;
-}
-
-/****************************************************************************
- *
- * Camera control
- *
- ***************************************************************************/
-
-
-static int se401_send_pict(struct usb_se401 *se401)
-{
-       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
-       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
-       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
-       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
-       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
-               
-       return 0;
-}
-
-static void se401_set_exposure(struct usb_se401 *se401, int brightness)
-{
-       int integration=brightness<<5;
-       
-       if (flickerless==50) {
-               integration=integration-integration%106667;
-       }
-       if (flickerless==60) {
-               integration=integration-integration%88889;
-       }
-       se401->brightness=integration>>5;
-       se401->expose_h=(integration>>16)&0xff;
-       se401->expose_m=(integration>>8)&0xff;
-       se401->expose_l=integration&0xff;
-}
-
-static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
-{
-       p->brightness=se401->brightness;
-       if (se401->enhance) {
-               p->whiteness=32768;
-       } else {
-               p->whiteness=0;
-       }
-       p->colour=65535;
-       p->contrast=65535;
-       p->hue=se401->rgain<<10;
-       p->palette=se401->palette;
-       p->depth=3; /* rgb24 */
-       return 0;
-}
-
-
-static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
-{
-       if (p->palette != VIDEO_PALETTE_RGB24)
-               return 1;
-       se401->palette=p->palette;
-       if (p->hue!=se401->hue) {
-               se401->rgain= p->hue>>10;
-               se401->bgain= 0x40-(p->hue>>10);
-               se401->hue=p->hue;
-       }
-       if (p->brightness!=se401->brightness) {
-               se401_set_exposure(se401, p->brightness);
-       }
-       if (p->whiteness>=32768) {
-               se401->enhance=1;
-       } else {
-               se401->enhance=0;
-       }
-       se401_send_pict(se401);
-       se401_send_pict(se401);
-       return 0;
-}
-
-/*
-       Hyundai have some really nice docs about this and other sensor related
-       stuff on their homepage: www.hei.co.kr
-*/
-static void se401_auto_resetlevel(struct usb_se401 *se401)
-{
-       unsigned int ahrc, alrc;
-       int oldreset=se401->resetlevel;
-
-       /* For some reason this normally read-only register doesn't get reset
-          to zero after reading them just once...
-        */
-       se401_get_feature(se401, HV7131_REG_HIREFNOH); 
-       se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       se401_get_feature(se401, HV7131_REG_LOREFNOH);
-       se401_get_feature(se401, HV7131_REG_LOREFNOL);
-       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + 
-           se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
-           se401_get_feature(se401, HV7131_REG_LOREFNOL);
-
-       /* Not an exact science, but it seems to work pretty well... */
-       if (alrc > 10) {
-               while (alrc>=10 && se401->resetlevel < 63) {
-                       se401->resetlevel++;
-                       alrc /=2;
-               }
-       } else if (ahrc > 20) {
-               while (ahrc>=20 && se401->resetlevel > 0) {
-                       se401->resetlevel--;
-                       ahrc /=2;
-               }
-       }
-       if (se401->resetlevel!=oldreset)
-               se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
-
-       return;
-}
-
-/* irq handler for snapshot button */
-static void se401_button_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_se401 *se401 = urb->context;
-       int status;
-       
-       if (!se401->dev) {
-               info("ohoh: device vapourished");
-               return;
-       }
-       
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-               goto exit;
-       }
-
-       if (urb->actual_length >=2) {
-               if (se401->button)
-                       se401->buttonpressed=1;
-       }
-exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
-               err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, status);
-}
-
-static void se401_video_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_se401 *se401 = urb->context;
-       int length = urb->actual_length;
-
-       /* ohoh... */
-       if (!se401->streaming)
-               return;
-
-       if (!se401->dev) {
-               info ("ohoh: device vapourished");
-               return;
-       }
-
-       /* 0 sized packets happen if we are to fast, but sometimes the camera
-          keeps sending them forever...
-        */
-       if (length && !urb->status) {
-               se401->nullpackets=0;
-               switch(se401->scratch[se401->scratch_next].state) {
-                       case BUFFER_READY:
-                       case BUFFER_BUSY: {
-                               se401->dropped++;
-                               break;
-                       }
-                       case BUFFER_UNUSED: {
-                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
-                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
-                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
-                               se401->scratch[se401->scratch_next].length=length;
-                               if (waitqueue_active(&se401->wq)) {
-                                       wake_up_interruptible(&se401->wq);
-                               }
-                               se401->scratch_overflow=0;
-                               se401->scratch_next++;
-                               if (se401->scratch_next>=SE401_NUMSCRATCH)
-                                       se401->scratch_next=0;
-                               break;
-                       }
-               }
-               se401->bayeroffset+=length;
-               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
-                       se401->bayeroffset=0;
-               }
-       } else {
-               se401->nullpackets++;
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       if (waitqueue_active(&se401->wq)) {
-                               wake_up_interruptible(&se401->wq);
-                       }               
-               }
-       }
-
-       /* Resubmit urb for new data */
-       urb->status=0;
-       urb->dev=se401->dev;
-       if(usb_submit_urb(urb, GFP_KERNEL))
-               info("urb burned down");
-       return;
-}
-
-static void se401_send_size(struct usb_se401 *se401, int width, int height)
-{
-       int i=0;
-       int mode=0x03; /* No compression */
-       int sendheight=height;
-       int sendwidth=width;
-
-       /* JangGu compression can only be used with the camera supported sizes,
-          but bayer seems to work with any size that fits on the sensor.
-          We check if we can use compression with the current size with either
-          4 or 16 times subcapturing, if not we use uncompressed bayer data
-          but this will result in cutouts of the maximum size....
-        */
-       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
-               i++;
-       while (i<se401->sizes) {
-               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x40;
-               }
-               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x42;
-               }
-               i++;
-       }
-
-       se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
-       se401_set_feature(se401, SE401_OPERATINGMODE, mode);
-
-       if (mode==0x03) {
-               se401->format=FMT_BAYER;
-       } else {
-               se401->format=FMT_JANGGU;
-       }
-
-       return;
-}
-
-/*
-       In this function se401_send_pict is called several times,
-       for some reason (depending on the state of the sensor and the phase of
-       the moon :) doing this only in either place doesn't always work...
-*/
-static int se401_start_stream(struct usb_se401 *se401)
-{
-       struct urb *urb;
-       int err=0, i;
-       se401->streaming=1;
-
-        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
-        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
-       /* Set picture settings */
-       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
-       se401_send_pict(se401);
-
-       se401_send_size(se401, se401->cwidth, se401->cheight);
-
-       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
-
-       /* Do some memory allocation */
-       for (i=0; i<SE401_NUMFRAMES; i++) {
-               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
-               se401->frame[i].curpix=0;
-       }
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
-       }
-
-       se401->bayeroffset=0;
-       se401->scratch_next=0;
-       se401->scratch_use=0;
-       se401->scratch_overflow=0;
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
-               se401->scratch[i].state=BUFFER_UNUSED;
-       }
-
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               urb=usb_alloc_urb(0, GFP_KERNEL);
-               if(!urb)
-                       return -ENOMEM;
-
-               usb_fill_bulk_urb(urb, se401->dev,
-                       usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
-                       se401->sbuf[i].data, SE401_PACKETSIZE,
-                       se401_video_irq,
-                       se401);
-
-               se401->urb[i]=urb;
-
-               err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
-               if(err)
-                       err("urb burned down");
-       }
-
-       se401->framecount=0;
-
-       return 0;
-}
-
-static int se401_stop_stream(struct usb_se401 *se401)
-{
-       int i;
-
-       if (!se401->streaming || !se401->dev)
-               return 1;
-
-       se401->streaming=0;
-
-       se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
-
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-
-       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
-               usb_kill_urb(se401->urb[i]);
-               usb_free_urb(se401->urb[i]);
-               se401->urb[i]=NULL;
-               kfree(se401->sbuf[i].data);
-       }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               kfree(se401->scratch[i].data);
-               se401->scratch[i].data=NULL;
-       }
-
-       return 0;
-}
-
-static int se401_set_size(struct usb_se401 *se401, int width, int height)
-{
-       int wasstreaming=se401->streaming;
-       /* Check to see if we need to change */
-       if (se401->cwidth==width && se401->cheight==height)
-               return 0;
-
-       /* Check for a valid mode */
-       if (!width || !height)
-               return 1;
-       if ((width & 1) || (height & 1))
-               return 1;
-       if (width>se401->width[se401->sizes-1])
-               return 1;
-       if (height>se401->height[se401->sizes-1])
-               return 1;
-
-       /* Stop a current stream and start it again at the new size */
-       if (wasstreaming)
-               se401_stop_stream(se401);
-       se401->cwidth=width;
-       se401->cheight=height;
-       if (wasstreaming)
-               se401_start_stream(se401);
-       return 0;
-}
-
-
-/****************************************************************************
- *
- * Video Decoding
- *
- ***************************************************************************/
-
-/*
-       This shouldn't really be done in a v4l driver....
-       But it does make the image look a lot more usable.
-       Basically it lifts the dark pixels more than the light pixels.
-*/
-static inline void enhance_picture(unsigned char *frame, int len)
-{
-       while (len--) {
-               *frame=(((*frame^255)*(*frame^255))/255)^255;
-               frame++;
-       }
-}
-
-static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
-{
-       struct se401_frame *frame=&se401->frame[se401->curframe];
-       int linelength=se401->cwidth*3;
-
-       if (frame->curlinepix >= linelength) {
-               frame->curlinepix=0;
-               frame->curline+=linelength;
-       }
-
-       /* First three are absolute, all others relative.
-        * Format is rgb from right to left (mirrorred image), 
-        * we flip it to get bgr from left to right. */
-       if (frame->curlinepix < 3) {
-               *(frame->curline-frame->curlinepix)=1+data*4;
-       } else {
-               *(frame->curline-frame->curlinepix)=
-                   *(frame->curline-frame->curlinepix+3)+data*4;
-       }
-       frame->curlinepix++;
-}
-
-static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
-{
-       int pos=0;
-       int vlc_cod=0;
-       int vlc_size=0;
-       int vlc_data=0;
-       int bit_cur;
-       int bit;
-       data+=4;
-       while (pos < packetlength) {
-               bit_cur=8;
-               while (bit_cur && bit_exp) {
-                       bit=((*data)>>(bit_cur-1))&1;
-                       if (!vlc_cod) {
-                               if (bit) {
-                                       vlc_size++;
-                               } else {
-                                       if (!vlc_size) {
-                                               decode_JangGu_integrate(se401, 0);
-                                       } else {
-                                               vlc_cod=2;
-                                               vlc_data=0;
-                                       }
-                               }
-                       } else {
-                               if (vlc_cod==2) {
-                                       if (!bit)
-                                               vlc_data =  -(1<<vlc_size) + 1;
-                                       vlc_cod--;
-                               }
-                               vlc_size--;
-                               vlc_data+=bit<<vlc_size;
-                               if (!vlc_size) {
-                                       decode_JangGu_integrate(se401, vlc_data);
-                                       vlc_cod=0;
-                               }
-                       }
-                       bit_cur--;
-                       bit_exp--;
-               }
-               pos++;
-               data++;
-       }
-}
-
-static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
-{
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
-       int datapos=0;
-
-       /* New image? */
-       if (!se401->frame[se401->curframe].curpix) {
-               se401->frame[se401->curframe].curlinepix=0;
-               se401->frame[se401->curframe].curline=
-                   se401->frame[se401->curframe].data+
-                   se401->cwidth*3-1;
-               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
-                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
-               se401->vlcdatapos=0;
-       }
-       while (datapos < len) {
-               size=1024-se401->vlcdatapos;
-               if (size+datapos > len)
-                       size=len-datapos;
-               memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
-               se401->vlcdatapos+=size;
-               packetlength=0;
-               if (se401->vlcdatapos >= 4) {
-                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
-                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
-                       frameinfo=se401->vlcdata[0]&0xc0;
-                       packetlength=((bit_exp+47)>>4)<<1;
-                       if (packetlength > 1024) {
-                               se401->vlcdatapos=0;
-                               datapos=len;
-                               packetlength=0;
-                               se401->error++;
-                               se401->frame[se401->curframe].curpix=0;
-                       }
-               }
-               if (packetlength && se401->vlcdatapos >= packetlength) {
-                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
-                       se401->frame[se401->curframe].curpix+=pix_exp*3;
-                       datapos+=size-(se401->vlcdatapos-packetlength);
-                       se401->vlcdatapos=0;
-                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
-                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
-                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
-                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
-                                               se401->framecount++;
-                                               se401->readcount++;
-                                       }
-                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
-                                       }
-                               } else {
-                                       se401->error++;
-                               }
-                               se401->frame[se401->curframe].curpix=0;
-                               datapos=len;
-                       }
-               } else {
-                       datapos+=size;
-               }
-       }
-}
-
-static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
-{
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int offset=buffer->offset;
-       int datasize=se401->cwidth*se401->cheight;
-       struct se401_frame *frame=&se401->frame[se401->curframe];
-
-       unsigned char *framedata=frame->data, *curline, *nextline;
-       int width=se401->cwidth;
-       int blineoffset=0, bline;
-       int linelength=width*3, i;
-       
-
-       if (frame->curpix==0) {
-               if (frame->grabstate==FRAME_READY) {
-                       frame->grabstate=FRAME_GRABBING;
-               }
-               frame->curline=framedata+linelength;
-               frame->curlinepix=0;
-       }
-
-       if (offset!=frame->curpix) {
-               /* Regard frame as lost :( */
-               frame->curpix=0;
-               se401->error++;
-               return;
-       }
-
-       /* Check if we have to much data */
-       if (frame->curpix+len > datasize) {
-               len=datasize-frame->curpix;
-       }
-       if (se401->cheight%4)
-               blineoffset=1;
-       bline=frame->curpix/se401->cwidth+blineoffset;
-
-       curline=frame->curline;
-       nextline=curline+linelength;
-       if (nextline >= framedata+datasize*3)
-               nextline=curline;
-       while (len) {
-               if (frame->curlinepix>=width) {
-                       frame->curlinepix-=width;
-                       bline=frame->curpix/width+blineoffset;
-                       curline+=linelength*2;
-                       nextline+=linelength*2;
-                       if (curline >= framedata+datasize*3) {
-                               frame->curlinepix++;
-                               curline-=3;
-                               nextline-=3;
-                               len--;
-                               data++;
-                               frame->curpix++;
-                       }
-                       if (nextline >= framedata+datasize*3)
-                               nextline=curline;
-               }
-               if ((bline&1)) {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+2)=*data;
-                               *(curline-1)=*data;
-                               *(nextline+2)=*data;
-                               *(nextline-1)=*data;
-                       } else {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
-                       }
-               } else {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
-                       } else {
-                               *curline=*data;
-                               *(curline-3)=*data;
-                               *nextline=*data;
-                               *(nextline-3)=*data;
-                       }
-               }
-               frame->curlinepix++;
-               curline-=3;
-               nextline-=3;
-               len--;
-               data++;
-               frame->curpix++;
-       }
-       frame->curline=curline;
-
-       if (frame->curpix>=datasize) {
-               /* Fix the top line */
-               framedata+=linelength;
-               for (i=0; i<linelength; i++) {
-                       framedata--;
-                       *framedata=*(framedata+linelength);
-               }
-               /* Fix the left side (green is already present) */
-               for (i=0; i<se401->cheight; i++) {
-                       *framedata=*(framedata+3);
-                       *(framedata+1)=*(framedata+4);
-                       *(framedata+2)=*(framedata+5);
-                       framedata+=linelength;
-               }
-               frame->curpix=0;
-               frame->grabstate=FRAME_DONE;
-               se401->framecount++;
-               se401->readcount++;
-               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
-               }
-       }
-}
-
-static int se401_newframe(struct usb_se401 *se401, int framenr)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int errors=0;
-
-       while (se401->streaming &&
-           (se401->frame[framenr].grabstate==FRAME_READY ||
-            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
-               if(!se401->frame[framenr].curpix) {
-                       errors++;
-               }
-               wait_interruptible(
-                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
-                   &se401->wq,
-                   &wait
-               );
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       se401->nullpackets=0;
-                       info("to many null length packets, restarting capture");
-                       se401_stop_stream(se401);
-                       se401_start_stream(se401);                      
-               } else {
-                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
-                               se401->frame[framenr].grabstate=FRAME_ERROR;
-                               return -EIO;
-                       }
-                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
-                       if (se401->format==FMT_JANGGU) {
-                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
-                       } else {
-                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
-                       }
-                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
-                       se401->scratch_use++;
-                       if (se401->scratch_use>=SE401_NUMSCRATCH)
-                               se401->scratch_use=0;
-                       if (errors > SE401_MAX_ERRORS) {
-                               errors=0;
-                               info("to much errors, restarting capture");
-                               se401_stop_stream(se401);
-                               se401_start_stream(se401);
-                       }
-               }
-       }
-
-       if (se401->frame[framenr].grabstate==FRAME_DONE)
-               if (se401->enhance)
-                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
-       return 0;
-}
-
-static void usb_se401_remove_disconnected (struct usb_se401 *se401)
-{
-       int i;
-
-        se401->dev = NULL;
-
-       for (i=0; i<SE401_NUMSBUF; i++)
-               if (se401->urb[i]) {
-                       usb_kill_urb(se401->urb[i]);
-                       usb_free_urb(se401->urb[i]);
-                       se401->urb[i] = NULL;
-                       kfree(se401->sbuf[i].data);
-               }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               kfree(se401->scratch[i].data);
-       }
-       if (se401->inturb) {
-               usb_kill_urb(se401->inturb);
-               usb_free_urb(se401->inturb);
-       }
-        info("%s disconnected", se401->camera_name);
-
-        /* Free the memory */
-       kfree(se401->width);
-       kfree(se401->height);
-       kfree(se401);
-}
-
-
-
-/****************************************************************************
- *
- * Video4Linux
- *
- ***************************************************************************/
-
-
-static int se401_open(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       int err = 0;
-
-       if (se401->user)
-               return -EBUSY;
-       se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
-       if (se401->fbuf)
-               file->private_data = dev;
-       else 
-               err = -ENOMEM;
-       se401->user = !err;
-
-       return err;
-}
-
-static int se401_close(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = file->private_data;
-        struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       int i;
-
-       rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
-        if (se401->removed) {
-               usb_se401_remove_disconnected(se401);
-               info("device unregistered");
-       } else {
-               for (i=0; i<SE401_NUMFRAMES; i++)
-                       se401->frame[i].grabstate=FRAME_UNUSED;
-               if (se401->streaming)
-                       se401_stop_stream(se401);
-               se401->user=0;
-       }
-       file->private_data = NULL;
-       return 0;
-}
-
-static int se401_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-        struct usb_se401 *se401 = (struct usb_se401 *)vdev;
-
-        if (!se401->dev)
-                return -EIO;
-
-        switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *b = arg;
-               strcpy(b->name, se401->camera_name);
-               b->type = VID_TYPE_CAPTURE;
-               b->channels = 1;
-               b->audios = 0;
-               b->maxwidth = se401->width[se401->sizes-1];
-               b->maxheight = se401->height[se401->sizes-1];
-               b->minwidth = se401->width[0];
-               b->minheight = se401->height[0];
-               return 0;
-       }
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-
-               if (v->channel != 0)
-                       return -EINVAL;
-               v->flags = 0;
-               v->tuners = 0;
-               v->type = VIDEO_TYPE_CAMERA;
-               strcpy(v->name, "Camera");
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-
-               if (v->channel != 0)
-                       return -EINVAL;
-               return 0;
-       }
-        case VIDIOCGPICT:
-        {
-               struct video_picture *p = arg;
-
-               se401_get_pict(se401, p);
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *p = arg;
-
-               if (se401_set_pict(se401, p))
-                       return -EINVAL;
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *vw = arg;
-
-               if (vw->flags)
-                       return -EINVAL;
-               if (vw->clipcount)
-                       return -EINVAL;
-               if (se401_set_size(se401, vw->width, vw->height))
-                       return -EINVAL;
-               return 0;
-        }
-       case VIDIOCGWIN:
-       {
-               struct video_window *vw = arg;
-
-               vw->x = 0;               /* FIXME */
-               vw->y = 0;
-               vw->chromakey = 0;
-               vw->flags = 0;
-               vw->clipcount = 0;
-               vw->width = se401->cwidth;
-               vw->height = se401->cheight;
-               return 0;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vm = arg;
-               int i;
-
-               memset(vm, 0, sizeof(*vm));
-               vm->size = SE401_NUMFRAMES * se401->maxframesize;
-               vm->frames = SE401_NUMFRAMES;
-               for (i=0; i<SE401_NUMFRAMES; i++)
-                       vm->offsets[i] = se401->maxframesize * i;
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-
-               if (vm->format != VIDEO_PALETTE_RGB24)
-                       return -EINVAL;
-               if (vm->frame >= SE401_NUMFRAMES)
-                       return -EINVAL;
-               if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
-                       return -EBUSY;
-
-               /* Is this according to the v4l spec??? */
-               if (se401_set_size(se401, vm->width, vm->height))
-                       return -EINVAL;
-               se401->frame[vm->frame].grabstate=FRAME_READY;
-
-               if (!se401->streaming)
-                       se401_start_stream(se401);
-
-               /* Set the picture properties */
-               if (se401->framecount==0)
-                       se401_send_pict(se401);
-               /* Calibrate the reset level after a few frames. */
-               if (se401->framecount%20==1)
-                       se401_auto_resetlevel(se401);
-
-               return 0;
-       }
-       case VIDIOCSYNC:
-       {
-               int *frame = arg;
-               int ret=0;
-
-               if(*frame <0 || *frame >= SE401_NUMFRAMES)
-                       return -EINVAL;
-
-               ret=se401_newframe(se401, *frame);
-               se401->frame[*frame].grabstate=FRAME_UNUSED;
-               return ret;
-       }
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vb = arg;
-
-               memset(vb, 0, sizeof(*vb));
-               return 0;
-       }
-       case VIDIOCKEY:
-               return 0;
-       case VIDIOCCAPTURE:
-               return -EINVAL;
-       case VIDIOCSFBUF:
-               return -EINVAL;
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-               return -EINVAL;
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               return -EINVAL;
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-        default:
-                return -ENOIOCTLCMD;
-        } /* end switch */
-
-        return 0;
-}
-
-static int se401_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);
-}
-
-static ssize_t se401_read(struct file *file, char __user *buf,
-                    size_t count, loff_t *ppos)
-{
-       int realcount=count, ret=0;
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-
-
-       if (se401->dev == NULL)
-               return -EIO;
-       if (realcount > se401->cwidth*se401->cheight*3)
-               realcount=se401->cwidth*se401->cheight*3;
-
-       /* Shouldn't happen: */
-       if (se401->frame[0].grabstate==FRAME_GRABBING)
-               return -EBUSY;
-       se401->frame[0].grabstate=FRAME_READY;
-       se401->frame[1].grabstate=FRAME_UNUSED;
-       se401->curframe=0;
-
-       if (!se401->streaming)
-               se401_start_stream(se401);
-
-       /* Set the picture properties */
-       if (se401->framecount==0)
-               se401_send_pict(se401);
-       /* Calibrate the reset level after a few frames. */
-       if (se401->framecount%20==1)
-               se401_auto_resetlevel(se401);
-
-       ret=se401_newframe(se401, 0);
-
-       se401->frame[0].grabstate=FRAME_UNUSED;
-       if (ret)
-               return ret;     
-       if (copy_to_user(buf, se401->frame[0].data, realcount))
-               return -EFAULT;
-
-       return realcount;
-}
-
-static int se401_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       mutex_lock(&se401->lock);
-
-       if (se401->dev == NULL) {
-               mutex_unlock(&se401->lock);
-               return -EIO;
-       }
-       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-               mutex_unlock(&se401->lock);
-               return -EINVAL;
-       }
-       pos = (unsigned long)se401->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&se401->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       mutex_unlock(&se401->lock);
-
-        return 0;
-}
-
-static struct file_operations se401_fops = {
-       .owner =        THIS_MODULE,
-        .open =         se401_open,
-        .release =      se401_close,
-        .read =         se401_read,
-        .mmap =         se401_mmap,
-       .ioctl =        se401_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-static struct video_device se401_template = {
-       .owner =        THIS_MODULE,
-        .name =         "se401 USB camera",
-        .type =         VID_TYPE_CAPTURE,
-        .hardware =     VID_HARDWARE_SE401,
-       .fops =         &se401_fops,
-};
-
-
-
-/***************************/
-static int se401_init(struct usb_se401 *se401, int button)
-{
-        int i=0, rc;
-        unsigned char cp[0x40];
-       char temp[200];
-
-       /* led on */
-        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
-       /* get camera descriptor */
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
-       if (cp[1]!=0x41) {
-               err("Wrong descriptor type");
-               return 1;
-       }
-       sprintf (temp, "ExtraFeatures: %d", cp[3]);
-
-       se401->sizes=cp[4]+cp[5]*256;
-       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
-       if (!se401->width)
-               return 1;
-       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
-       if (!se401->height) {
-               kfree(se401->width);
-               return 1;
-       }
-       for (i=0; i<se401->sizes; i++) {
-                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
-                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
-       }
-       sprintf (temp, "%s Sizes:", temp);
-       for (i=0; i<se401->sizes; i++) {
-               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
-       }
-       info("%s", temp);
-       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
-
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
-       se401->cwidth=cp[0]+cp[1]*256;
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
-       se401->cheight=cp[0]+cp[1]*256;
-
-       if (!cp[2] && SE401_FORMAT_BAYER) {
-               err("Bayer format not supported!");
-               return 1;
-       }
-       /* set output mode (BAYER) */
-        se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
-
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
-       se401->brightness=cp[0]+cp[1]*256;
-       /* some default values */
-       se401->resetlevel=0x2d;
-       se401->rgain=0x20;
-       se401->ggain=0x20;
-       se401->bgain=0x20;
-       se401_set_exposure(se401, 20000);
-       se401->palette=VIDEO_PALETTE_RGB24;
-       se401->enhance=1;
-       se401->dropped=0;
-       se401->error=0;
-       se401->framecount=0;
-       se401->readcount=0;
-
-       /* Start interrupt transfers for snapshot button */
-       if (button) {
-               se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
-               if (!se401->inturb) {
-                       info("Allocation of inturb failed");
-                       return 1;
-               }
-               usb_fill_int_urb(se401->inturb, se401->dev,
-                   usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
-                   &se401->button, sizeof(se401->button),
-                   se401_button_irq,
-                   se401,
-                   8
-               );
-               if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
-                       info("int urb burned down");
-                       return 1;
-               }
-       } else
-               se401->inturb=NULL;
-
-        /* Flash the led */
-        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
-        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-
-        return 0;
-}
-
-static int se401_probe(struct usb_interface *intf,
-       const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-        struct usb_interface_descriptor *interface;
-        struct usb_se401 *se401;
-        char *camera_name=NULL;
-       int button=1;
-
-        /* We don't handle multi-config cameras */
-        if (dev->descriptor.bNumConfigurations != 1)
-                return -ENODEV;
-
-        interface = &intf->cur_altsetting->desc;
-
-        /* Is it an se401? */
-        if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
-            le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
-                camera_name="Endpoints/Aox SE401";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
-            le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
-                camera_name="Philips PCVC665K";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
-               camera_name="Kensington VideoCAM 67014";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
-               camera_name="Kensington VideoCAM 6701(5/7)";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
-               camera_name="Kensington VideoCAM 67016";
-               button=0;
-       } else
-               return -ENODEV;
-
-        /* Checking vendor/product should be enough, but what the hell */
-        if (interface->bInterfaceClass != 0x00)
-               return -ENODEV;
-        if (interface->bInterfaceSubClass != 0x00)
-               return -ENODEV;
-
-        /* We found one */
-        info("SE401 camera found: %s", camera_name);
-
-        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
-                err("couldn't kmalloc se401 struct");
-               return -ENOMEM;
-        }
-
-        se401->dev = dev;
-        se401->iface = interface->bInterfaceNumber;
-        se401->camera_name = camera_name;
-
-       info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
-
-        if (se401_init(se401, button)) {
-               kfree(se401);
-               return -EIO;
-       }
-
-       memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
-       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
-       init_waitqueue_head(&se401->wq);
-       mutex_init(&se401->lock);
-       wmb();
-
-       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               kfree(se401);
-               err("video_register_device failed");
-               return -EIO;
-       }
-       info("registered new video device: video%d", se401->vdev.minor);
-
-       usb_set_intfdata (intf, se401);
-        return 0;
-}
-
-static void se401_disconnect(struct usb_interface *intf)
-{
-       struct usb_se401 *se401 = usb_get_intfdata (intf);
-
-       usb_set_intfdata (intf, NULL);
-       if (se401) {
-               video_unregister_device(&se401->vdev);
-               if (!se401->user){
-                       usb_se401_remove_disconnected(se401);
-               } else {
-                       se401->frame[0].grabstate = FRAME_ERROR;
-                       se401->frame[0].grabstate = FRAME_ERROR;
-
-                       se401->streaming = 0;
-
-                       wake_up_interruptible(&se401->wq);
-                       se401->removed = 1;
-               }
-       }
-}
-
-static struct usb_driver se401_driver = {
-        .name          = "se401",
-        .id_table      = device_table,
-       .probe          = se401_probe,
-        .disconnect    = se401_disconnect,
-};
-
-
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init usb_se401_init(void)
-{
-       info("SE401 usb camera driver version %s registering", version);
-       if (flickerless)
-               if (flickerless!=50 && flickerless!=60) {
-                       info("Invallid flickerless value, use 0, 50 or 60.");
-                       return -1;
-       }
-       return usb_register(&se401_driver);
-}
-
-static void __exit usb_se401_exit(void)
-{
-       usb_deregister(&se401_driver);
-       info("SE401 driver deregistered");
-}
-
-module_init(usb_se401_init);
-module_exit(usb_se401_exit);
diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h
deleted file mode 100644 (file)
index e88a40d..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-
-#ifndef __LINUX_se401_H
-#define __LINUX_se401_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <linux/smp_lock.h>
-#include <linux/mutex.h>
-
-#define se401_DEBUG    /* Turn on debug messages */
-
-#ifdef se401_DEBUG
-#  define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
-#else
-#  define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* An almost drop-in replacement for sleep_on_interruptible */
-#define wait_interruptible(test, queue, wait) \
-{ \
-       add_wait_queue(queue, wait); \
-       set_current_state(TASK_INTERRUPTIBLE); \
-       if (test) \
-               schedule(); \
-       remove_wait_queue(queue, wait); \
-       set_current_state(TASK_RUNNING); \
-       if (signal_pending(current)) \
-               break; \
-}
-
-#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
-#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
-#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
-#define SE401_REQ_CAPTURE_FRAME                        0x43
-#define SE401_REQ_GET_BRT                      0x44
-#define SE401_REQ_SET_BRT                      0x45
-#define SE401_REQ_GET_WIDTH                    0x4c
-#define SE401_REQ_SET_WIDTH                    0x4d
-#define SE401_REQ_GET_HEIGHT                   0x4e
-#define SE401_REQ_SET_HEIGHT                   0x4f
-#define SE401_REQ_GET_OUTPUT_MODE              0x50
-#define SE401_REQ_SET_OUTPUT_MODE              0x51
-#define SE401_REQ_GET_EXT_FEATURE              0x52
-#define SE401_REQ_SET_EXT_FEATURE              0x53
-#define SE401_REQ_CAMERA_POWER                 0x56
-#define SE401_REQ_LED_CONTROL                  0x57
-#define SE401_REQ_BIOS                         0xff
-
-#define SE401_BIOS_READ                                0x07
-
-#define SE401_FORMAT_BAYER     0x40
-
-/* Hyundai hv7131b registers
-   7121 and 7141 should be the same (haven't really checked...) */
-/* Mode registers: */
-#define HV7131_REG_MODE_A              0x00
-#define HV7131_REG_MODE_B              0x01
-#define HV7131_REG_MODE_C              0x02
-/* Frame registers: */
-#define HV7131_REG_FRSU                0x10
-#define HV7131_REG_FRSL                0x11
-#define HV7131_REG_FCSU                0x12
-#define HV7131_REG_FCSL                0x13
-#define HV7131_REG_FWHU                0x14
-#define HV7131_REG_FWHL                0x15
-#define HV7131_REG_FWWU                0x16
-#define HV7131_REG_FWWL                0x17
-/* Timing registers: */
-#define HV7131_REG_THBU                0x20
-#define HV7131_REG_THBL                0x21
-#define HV7131_REG_TVBU                0x22
-#define HV7131_REG_TVBL                0x23
-#define HV7131_REG_TITU                0x25
-#define HV7131_REG_TITM                0x26
-#define HV7131_REG_TITL                0x27
-#define HV7131_REG_TMCD                0x28
-/* Adjust Registers: */
-#define HV7131_REG_ARLV                0x30
-#define HV7131_REG_ARCG                0x31
-#define HV7131_REG_AGCG                0x32
-#define HV7131_REG_ABCG                0x33
-#define HV7131_REG_APBV                0x34
-#define HV7131_REG_ASLP                0x54
-/* Offset Registers: */
-#define HV7131_REG_OFSR                0x50
-#define HV7131_REG_OFSG                0x51
-#define HV7131_REG_OFSB                0x52
-/* REset level statistics registers: */
-#define HV7131_REG_LOREFNOH    0x57
-#define HV7131_REG_LOREFNOL    0x58
-#define HV7131_REG_HIREFNOH    0x59
-#define HV7131_REG_HIREFNOL    0x5a
-
-/* se401 registers */
-#define SE401_OPERATINGMODE    0x2000
-
-
-/* size of usb transfers */
-#define SE401_PACKETSIZE       4096
-/* number of queued bulk transfers to use, should be about 8 */
-#define SE401_NUMSBUF          1
-/* read the usb specs for this one :) */
-#define SE401_VIDEO_ENDPOINT   1
-#define SE401_BUTTON_ENDPOINT  2
-/* number of frames supported by the v4l part */
-#define SE401_NUMFRAMES                2
-/* scratch buffers for passing data to the decoders */
-#define SE401_NUMSCRATCH       32
-/* maximum amount of data in a JangGu packet */
-#define SE401_VLCDATALEN       1024
-/* number of nul sized packets to receive before kicking the camera */
-#define SE401_MAX_NULLPACKETS  4000
-/* number of decoding errors before kicking the camera */
-#define SE401_MAX_ERRORS       200
-
-struct usb_device;
-
-struct se401_sbuf {
-       unsigned char *data;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-enum {
-       FMT_BAYER,
-       FMT_JANGGU,
-};
-
-enum {
-       BUFFER_UNUSED,
-       BUFFER_READY,
-       BUFFER_BUSY,
-       BUFFER_DONE,
-};
-
-struct se401_scratch {
-       unsigned char *data;
-       volatile int state;
-       int offset;
-       int length;
-};
-
-struct se401_frame {
-       unsigned char *data;            /* Frame buffer */
-
-       volatile int grabstate; /* State of grabbing */
-
-       unsigned char *curline;
-       int curlinepix;
-       int curpix;
-};
-
-struct usb_se401 {
-       struct video_device vdev;
-
-       /* Device structure */
-       struct usb_device *dev;
-
-       unsigned char iface;
-
-       char *camera_name;
-
-       int change;
-       int brightness;
-       int hue;
-       int rgain;
-       int ggain;
-       int bgain;
-       int expose_h;
-       int expose_m;
-       int expose_l;
-       int resetlevel;
-       
-       int enhance;
-
-       int format;
-       int sizes;
-       int *width;
-       int *height;
-       int cwidth;             /* current width */
-       int cheight;            /* current height */
-       int palette;
-       int maxframesize;
-       int cframesize;         /* current framesize */
-
-       struct mutex lock;
-       int user;               /* user count for exclusive use */
-       int removed;            /* device disconnected */
-
-       int streaming;          /* Are we streaming video? */
-
-       char *fbuf;             /* Videodev buffer area */
-
-       struct urb *urb[SE401_NUMSBUF];
-       struct urb *inturb;
-       
-       int button;
-       int buttonpressed;
-
-       int curframe;           /* Current receiving frame */
-       struct se401_frame frame[SE401_NUMFRAMES];      
-       int readcount;
-       int framecount;
-       int error;
-       int dropped;
-
-       int scratch_next;
-       int scratch_use;
-       int scratch_overflow;
-       struct se401_scratch scratch[SE401_NUMSCRATCH];
-
-       /* Decoder specific data: */
-       unsigned char vlcdata[SE401_VLCDATALEN];
-       int vlcdatapos;
-       int bayeroffset;
-
-       struct se401_sbuf sbuf[SE401_NUMSBUF];
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int nullpackets;
-};
-
-
-
-#endif
-
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
deleted file mode 100644 (file)
index 1d70a62..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _SN9C102_H_
-#define _SN9C102_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/stddef.h>
-
-#include "sn9c102_sensor.h"
-
-/*****************************************************************************/
-
-#define SN9C102_DEBUG
-#define SN9C102_DEBUG_LEVEL       2
-#define SN9C102_MAX_DEVICES       64
-#define SN9C102_PRESERVE_IMGSCALE 0
-#define SN9C102_FORCE_MUNMAP      0
-#define SN9C102_MAX_FRAMES        32
-#define SN9C102_URBS              2
-#define SN9C102_ISO_PACKETS       7
-#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT      300
-#define SN9C102_FRAME_TIMEOUT     2
-
-/*****************************************************************************/
-
-enum sn9c102_bridge {
-       BRIDGE_SN9C101 = 0x01,
-       BRIDGE_SN9C102 = 0x02,
-       BRIDGE_SN9C103 = 0x04,
-};
-
-SN9C102_ID_TABLE
-SN9C102_SENSOR_TABLE
-
-enum sn9c102_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct sn9c102_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum sn9c102_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum sn9c102_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum sn9c102_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum sn9c102_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-typedef char sn9c103_sof_header_t[18];
-typedef char sn9c102_sof_header_t[12];
-typedef char sn9c102_eof_header_t[4];
-
-struct sn9c102_sysfs_attr {
-       u8 reg, i2c_reg;
-       sn9c103_sof_header_t frame_header;
-};
-
-struct sn9c102_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
-
-struct sn9c102_device {
-       struct video_device* v4ldev;
-
-       enum sn9c102_bridge bridge;
-       struct sn9c102_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[SN9C102_URBS];
-       void* transfer_buffer[SN9C102_URBS];
-       u8* control_buffer;
-
-       struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum sn9c102_io_method io;
-       enum sn9c102_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct sn9c102_sysfs_attr sysfs;
-       sn9c103_sof_header_t sof_header;
-       u16 reg[63];
-
-       struct sn9c102_module_param module_param;
-
-       enum sn9c102_dev_state state;
-       u8 users;
-
-       struct mutex dev_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
-{
-       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
-               return cam;
-
-       return NULL;
-}
-
-
-void
-sn9c102_attach_sensor(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef SN9C102_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("sn9c102: " fmt "\n", ## args);               \
-               else if ((level) == 3)                                        \
-                       pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-         __FUNCTION__, __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _SN9C102_H_ */
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
deleted file mode 100644 (file)
index 4c6cc63..0000000
+++ /dev/null
@@ -1,2919 +0,0 @@
-/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "sn9c102.h"
-
-/*****************************************************************************/
-
-#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
-#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.27"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
-
-MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
-MODULE_VERSION(SN9C102_MODULE_VERSION);
-MODULE_LICENSE(SN9C102_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
-                 " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = 
-                               SN9C102_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
-                                       SN9C102_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                 "\n<n[,...]> Timeout for a video frame in seconds."
-                 "\nThis parameter is specific for each detected camera."
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
-                 "\n");
-
-#ifdef SN9C102_DEBUG
-static unsigned short debug = SN9C102_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
-                 "\n");
-#endif
-
-/*****************************************************************************/
-
-static sn9c102_sof_header_t sn9c102_sof_header[] = {
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
-};
-
-static sn9c103_sof_header_t sn9c103_sof_header[] = {
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
-};
-
-static sn9c102_eof_header_t sn9c102_eof_header[] = {
-       {0x00, 0x00, 0x00, 0x00},
-       {0x40, 0x00, 0x00, 0x00},
-       {0x80, 0x00, 0x00, 0x00},
-       {0xc0, 0x00, 0x00, 0x00},
-};
-
-/*****************************************************************************/
-
-static u32 
-sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
-                        enum sn9c102_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > SN9C102_MAX_FRAMES)
-               count = SN9C102_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void sn9c102_release_buffers(struct sn9c102_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
-{
-       struct sn9c102_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       int i, res;
-
-       if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
-               return -1;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             index, 0, buff, sizeof(buff),
-                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
-       if (res < 0) {
-               DBG(3, "Failed to write registers (index 0x%02X, error %d)",
-                   index, res);
-               return -1;
-       }
-
-       for (i = 0; i < sizeof(buff); i++)
-               cam->reg[index+i] = buff[i];
-
-       return 0;
-}
-
-
-int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       if (index >= ARRAY_SIZE(cam->reg))
-               return -1;
-
-       *buff = value;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (value 0x%02X, index "
-                      "0x%02X, error %d)", value, index, res);
-               return -1;
-       }
-
-       cam->reg[index] = value;
-
-       return 0;
-}
-
-
-/* NOTE: reading some registers always returns 0 */
-static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-                   index, res);
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
-{
-       if (index >= ARRAY_SIZE(cam->reg))
-               return -1;
-
-       return cam->reg[index];
-}
-
-
-static int
-sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
-{
-       int i, r;
-
-       for (i = 1; i <= 5; i++) {
-               r = sn9c102_read_reg(cam, 0x08);
-               if (r < 0)
-                       return -EIO;
-               if (r & 0x04)
-                       return 0;
-               if (sensor->frequency & SN9C102_I2C_400KHZ)
-                       udelay(5*16);
-               else
-                       udelay(16*16);
-       }
-       return -EBUSY;
-}
-
-
-static int
-sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, 
-                              struct sn9c102_sensor* sensor)
-{
-       int r;
-       r = sn9c102_read_reg(cam, 0x08);
-       return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
-}
-
-
-static int
-sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, 
-                               struct sn9c102_sensor* sensor)
-{
-       int r;
-       r = sn9c102_read_reg(cam, 0x08);
-       return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
-}
-
-
-int 
-sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
-                         struct sn9c102_sensor* sensor, u8 data0, u8 data1,
-                         u8 n, u8 buffer[])
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       /* Write cycle */
-       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
-       data[1] = data0; /* I2C slave id */
-       data[2] = data1; /* address */
-       data[7] = 0x10;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_wait(cam, sensor);
-
-       /* Read cycle - n bytes */
-       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
-                 (n << 4) | 0x02;
-       data[1] = data0;
-       data[7] = 0x10;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_wait(cam, sensor);
-
-       /* The first read byte will be placed in data[4] */
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_detect_read_error(cam, sensor);
-
-       PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
-             data[4]);
-
-       if (err) {
-               DBG(3, "I2C read failed for %s image sensor", sensor->name);
-               return -1;
-       }
-
-       if (buffer)
-               memcpy(buffer, data, sizeof(buffer));
-
-       return (int)data[4];
-}
-
-
-int 
-sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
-                          struct sn9c102_sensor* sensor, u8 n, u8 data0,
-                          u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       /* Write cycle. It usually is address + value */
-       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
-                 | ((n - 1) << 4);
-       data[1] = data0;
-       data[2] = data1;
-       data[3] = data2;
-       data[4] = data3;
-       data[5] = data4;
-       data[6] = data5;
-       data[7] = 0x14;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_wait(cam, sensor);
-       err += sn9c102_i2c_detect_write_error(cam, sensor);
-
-       if (err)
-               DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
-             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
-             n, data0, data1, data2, data3, data4, data5);
-
-       return err ? -1 : 0;
-}
-
-
-int
-sn9c102_i2c_try_read(struct sn9c102_device* cam,
-                     struct sn9c102_sensor* sensor, u8 address)
-{
-       return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
-                                       address, 1, NULL);
-}
-
-
-int
-sn9c102_i2c_try_write(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor, u8 address, u8 value)
-{
-       return sn9c102_i2c_try_raw_write(cam, sensor, 3, 
-                                        sensor->i2c_slave_id, address,
-                                        value, 0, 0, 0);
-}
-
-
-int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
-{
-       return sn9c102_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
-{
-       return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-/*****************************************************************************/
-
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
-{
-       size_t soflen = 0, i;
-       u8 j, n = 0;
-
-       switch (cam->bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               soflen = sizeof(sn9c102_sof_header_t);
-               n = sizeof(sn9c102_sof_header) / soflen;
-               break;
-       case BRIDGE_SN9C103:
-               soflen = sizeof(sn9c103_sof_header_t);
-               n = sizeof(sn9c103_sof_header) / soflen;
-       }
-
-       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
-               for (j = 0; j < n; j++)
-                       /* The invariable part of the header is 6 bytes long */
-                       if ((cam->bridge != BRIDGE_SN9C103 &&
-                           !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
-                           (cam->bridge == BRIDGE_SN9C103 &&
-                           !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
-                               memcpy(cam->sof_header, mem + i, soflen);
-                               /* Skip the header */
-                               return mem + i + soflen;
-                       }
-
-       return NULL;
-}
-
-
-static void*
-sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
-{
-       size_t eoflen = sizeof(sn9c102_eof_header_t), i;
-       unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
-
-       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
-               return NULL; /* EOF header does not exist in compressed data */
-
-       for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
-               for (j = 0; j < n; j++)
-                       if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
-                               return mem + i;
-
-       return NULL;
-}
-
-
-static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
-{
-       struct sn9c102_device* cam = urb->context;
-       struct sn9c102_frame_t** f;
-       size_t imagesize, soflen;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       soflen = (cam->bridge) == BRIDGE_SN9C103 ?
-                                 sizeof(sn9c103_sof_header_t) :
-                                 sizeof(sn9c102_sof_header_t);
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int img, len, status;
-               void *pos, *sof, *eof;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               PDBGG("Isochrnous frame: length %u, #%u i", len, i);
-
-redo:
-               sof = sn9c102_find_sof_header(cam, pos, len);
-               if (likely(!sof)) {
-                       eof = sn9c102_find_eof_header(cam, pos, len);
-                       if ((*f)->state == F_GRABBING) {
-end_of_frame:
-                               img = len;
-
-                               if (eof)
-                                       img = (eof > pos) ? eof - pos - 1 : 0;
-
-                               if ((*f)->buf.bytesused+img > imagesize) {
-                                       u32 b;
-                                       b = (*f)->buf.bytesused + img -
-                                           imagesize;
-                                       img = imagesize - (*f)->buf.bytesused;
-                                       DBG(3, "Expected EOF not found: "
-                                              "video frame cut");
-                                       if (eof)
-                                               DBG(3, "Exceeded limit: +%u "
-                                                      "bytes", (unsigned)(b));
-                               }
-
-                               memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
-                                      img);
-
-                               if ((*f)->buf.bytesused == 0)
-                                       do_gettimeofday(&(*f)->buf.timestamp);
-
-                               (*f)->buf.bytesused += img;
-
-                               if ((*f)->buf.bytesused == imagesize ||
-                                   (cam->sensor.pix_format.pixelformat ==
-                                               V4L2_PIX_FMT_SN9C10X && eof)) {
-                                       u32 b;
-                                       b = (*f)->buf.bytesused;
-                                       (*f)->state = F_DONE;
-                                       (*f)->buf.sequence= ++cam->frame_count;
-                                       spin_lock(&cam->queue_lock);
-                                       list_move_tail(&(*f)->frame,
-                                                      &cam->outqueue);
-                                       if (!list_empty(&cam->inqueue))
-                                               (*f) = list_entry(
-                                                       cam->inqueue.next,
-                                                       struct sn9c102_frame_t,
-                                                       frame );
-                                       else
-                                               (*f) = NULL;
-                                       spin_unlock(&cam->queue_lock);
-                                       memcpy(cam->sysfs.frame_header,
-                                              cam->sof_header, soflen);
-                                       DBG(3, "Video frame captured: %lu "
-                                              "bytes", (unsigned long)(b));
-
-                                       if (!(*f))
-                                               goto resubmit_urb;
-
-                               } else if (eof) {
-                                       (*f)->state = F_ERROR;
-                                       DBG(3, "Not expected EOF after %lu "
-                                              "bytes of image data", 
-                                           (unsigned long)
-                                           ((*f)->buf.bytesused));
-                               }
-
-                               if (sof) /* (1) */
-                                       goto start_of_frame;
-
-                       } else if (eof) {
-                               DBG(3, "EOF without SOF");
-                               continue;
-
-                       } else {
-                               PDBGG("Ignoring pointless isochronous frame");
-                               continue;
-                       }
-
-               } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
-start_of_frame:
-                       (*f)->state = F_GRABBING;
-                       (*f)->buf.bytesused = 0;
-                       len -= (sof - pos);
-                       pos = sof;
-                       DBG(3, "SOF detected: new video frame");
-                       if (len)
-                               goto redo;
-
-               } else if ((*f)->state == F_GRABBING) {
-                       eof = sn9c102_find_eof_header(cam, pos, len);
-                       if (eof && eof < sof)
-                               goto end_of_frame; /* (1) */
-                       else {
-                               if (cam->sensor.pix_format.pixelformat ==
-                                   V4L2_PIX_FMT_SN9C10X) {
-                                       eof = sof - soflen;
-                                       goto end_of_frame;
-                               } else {
-                                       DBG(3, "SOF before expected EOF after "
-                                              "%lu bytes of image data", 
-                                           (unsigned long)
-                                           ((*f)->buf.bytesused));
-                                       goto start_of_frame;
-                               }
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int sn9c102_start_transfer(struct sn9c102_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1023};
-       const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1003};
-       const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
-                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
-                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < SN9C102_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < SN9C102_URBS; i++) {
-               urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = SN9C102_ISO_PACKETS;
-               urb->complete = sn9c102_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       /* Enable video */
-       if (!(cam->reg[0x01] & 0x04)) {
-               err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
-               if (err) {
-                       err = -EIO;
-                       DBG(1, "I/O hardware error");
-                       goto free_urbs;
-               }
-       }
-
-       err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < SN9C102_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < SN9C102_URBS) &&  cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int sn9c102_stop_transfer(struct sn9c102_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = SN9C102_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    SN9C102_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. "
-                      "To use it, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
-{
-       char str[5];
-       char* endp;
-       unsigned long val;
-
-       if (len < 4) {
-               strncpy(str, buff, len);
-               str[len+1] = '\0';
-       } else {
-               strncpy(str, buff, 4);
-               str[4] = '\0';
-       }
-
-       val = simple_strtoul(str, &endp, 0);
-
-       *count = 0;
-       if (val <= 0xff)
-               *count = (ssize_t)(endp - str);
-       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
-               *count += 1;
-
-       return (u8)val;
-}
-
-/*
-   NOTE 1: being inside one of the following methods implies that the v4l
-           device exists for sure (see kobjects and reference counters)
-   NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-} 
-
-
-static ssize_t 
-sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = sn9c102_strtou8(buf, len, &count);
-       if (index > 0x1f || !count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.reg = index;
-
-       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-} 
-
-
-static ssize_t
-sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
-       if (err) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t 
-sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = sn9c102_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.i2c_reg = index;
-
-       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-} 
-
-
-static ssize_t
-sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
-       if (err) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.i2c_reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       enum sn9c102_bridge bridge;
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       bridge = cam->bridge;
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count)
-               return -EINVAL;
-
-       switch (bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               if (value > 0x0f)
-                       return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
-                       res = sn9c102_store_val(cd, buf, len);
-               break;
-       case BRIDGE_SN9C103:
-               if (value > 0x7f)
-                       return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
-                       res = sn9c102_store_val(cd, buf, len);
-               break;
-       }
-
-       return res;
-}
-
-
-static ssize_t
-sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
-{
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x7f)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
-               res = sn9c102_store_val(cd, buf, len);
-
-       return res;
-}
-
-
-static ssize_t
-sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
-{
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x7f)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
-               res = sn9c102_store_val(cd, buf, len);
-
-       return res;
-}
-
-
-static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam)
-               return -ENODEV;
-
-       count = sizeof(cam->sysfs.frame_header);
-       memcpy(buf, cam->sysfs.frame_header, count);
-
-       DBG(3, "Frame header, read bytes: %zd", count);
-
-       return count;
-} 
-
-
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-                         sn9c102_show_reg, sn9c102_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-                         sn9c102_show_val, sn9c102_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-                         sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-                         sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
-static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
-static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
-static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
-                         sn9c102_show_frame_header, NULL);
-
-
-static void sn9c102_create_sysfs(struct sn9c102_device* cam)
-{
-       struct video_device *v4ldev = cam->v4ldev;
-
-       video_device_create_file(v4ldev, &class_device_attr_reg);
-       video_device_create_file(v4ldev, &class_device_attr_val);
-       video_device_create_file(v4ldev, &class_device_attr_frame_header);
-       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
-               video_device_create_file(v4ldev, &class_device_attr_green);
-       else if (cam->bridge == BRIDGE_SN9C103) {
-               video_device_create_file(v4ldev, &class_device_attr_blue);
-               video_device_create_file(v4ldev, &class_device_attr_red);
-       }
-       if (cam->sensor.sysfs_ops) {
-               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
-       }
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
-       else
-               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
-
-       return err ? -EIO : 0;
-}
-
-
-static int
-sn9c102_set_compression(struct sn9c102_device* cam,
-                        struct v4l2_jpegcompression* compression)
-{
-       int err = 0;
-
-       if (compression->quality == 0)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
-       else if (compression->quality == 1)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
-
-       return err ? -EIO : 0;
-}
-
-
-static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
-{
-       u8 r = 0;
-       int err = 0;
-
-       if (scale == 1)
-               r = cam->reg[0x18] & 0xcf;
-       else if (scale == 2) {
-               r = cam->reg[0x18] & 0xcf;
-               r |= 0x10;
-       } else if (scale == 4)
-               r = cam->reg[0x18] | 0x20;
-
-       err += sn9c102_write_reg(cam, r, 0x18);
-       if (err)
-               return -EIO;
-
-       PDBGG("Scaling factor: %u", scale);
-
-       return 0;
-}
-
-
-static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
-          v_start = (u8)(rect->top - s->cropcap.bounds.top),
-          h_size = (u8)(rect->width / 16),
-          v_size = (u8)(rect->height / 16);
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-       err += sn9c102_write_reg(cam, h_size, 0x15);
-       err += sn9c102_write_reg(cam, v_size, 0x16);
-       if (err)
-               return -EIO;
-
-       PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
-             "%u %u %u %u", h_start, v_start, h_size, v_size);
-
-       return 0;
-}
-
-
-static int sn9c102_init(struct sn9c102_device* cam)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
-       err += sn9c102_set_crop(cam, rect);
-       if (err)
-               return err;
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED))
-               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
-       else
-               err += sn9c102_set_compression(cam, &cam->compression);
-       err += sn9c102_set_pix_format(cam, &s->pix_format);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, &s->pix_format);
-       if (err)
-               return err;
-
-       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
-               DBG(3, "Compressed video format is active, quality %d",
-                   cam->compression.quality);
-       else
-               DBG(3, "Uncompressed video format is active");
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-
-static void sn9c102_release_resources(struct sn9c102_device* cam)
-{
-       mutex_lock(&sn9c102_sysfs_lock);
-
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-
-       usb_put_dev(cam->usbdev);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       kfree(cam->control_buffer);
-}
-
-/*****************************************************************************/
-
-static int sn9c102_open(struct inode* inode, struct file* filp)
-{
-       struct sn9c102_device* cam;
-       int err = 0;
-
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&sn9c102_disconnect))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&sn9c102_disconnect);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
-               if (err) {
-                       up_read(&sn9c102_disconnect);
-                       return err;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&sn9c102_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = sn9c102_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = sn9c102_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       sn9c102_empty_framequeues(cam);
-
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
-
-out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&sn9c102_disconnect);
-       return err;
-}
-
-
-static int sn9c102_release(struct inode* inode, struct file* filp)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       sn9c102_stop_transfer(cam);
-
-       sn9c102_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               sn9c102_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-}
-
-
-static ssize_t
-sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       struct sn9c102_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose "
-                      "the read method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       sn9c102_empty_framequeues(cam);
-               sn9c102_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       sn9c102_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return count;
-}
-
-
-static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       struct sn9c102_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
-                                            IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               sn9c102_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void sn9c102_vm_open(struct vm_area_struct* vma)
-{
-       struct sn9c102_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void sn9c102_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct sn9c102_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static struct vm_operations_struct sn9c102_vm_ops = {
-       .open = sn9c102_vm_open,
-       .close = sn9c102_vm_close,
-};
-
-
-static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &sn9c102_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-
-       sn9c102_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "sn9c102",
-               .version = SN9C102_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id && ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
-             (unsigned long)ctrl.id, (unsigned long)ctrl.value);
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_pix_format* pix_format = &(s->pix_format);
-       u8 scale;
-       const enum sn9c102_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       /* Preserve R,G or B origin */
-       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
-       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
-       if (rect->width < 16)
-               rect->width = 16;
-       if (rect->height < 16)
-               rect->height = 16;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-
-       rect->width &= ~15L;
-       rect->height &= ~15L;
-
-       if (SN9C102_PRESERVE_IMGSCALE) {
-               /* Calculate the actual scaling factor */
-               u32 a, b;
-               a = rect->width * rect->height;
-               b = pix_format->width * pix_format->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
-       } else
-               scale = 1;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               sn9c102_release_buffers(cam);
-
-       err = sn9c102_set_crop(cam, rect);
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-       err += sn9c102_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width/scale;
-       s->pix_format.height = rect->height/scale;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
-           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               sn9c102_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               sn9c102_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "bayer rgb");
-               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-       } else if (fmtd.index == 1) {
-               strcpy(fmtd.description, "compressed");
-               fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
-                            ? 0 : (pfmt->width * pfmt->priv) / 8;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
-                         void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       u8 scale;
-       const enum sn9c102_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       { /* calculate the actual scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
-       }
-
-       rect.width = scale * pix->width;
-       rect.height = scale * pix->height;
-
-       if (rect.width < 16)
-               rect.width = 16;
-       if (rect.height < 16)
-               rect.height = 16;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-
-       rect.width &= ~15L;
-       rect.height &= ~15L;
-
-       { /* adjust the scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
-       }
-
-       pix->width = rect.width / scale;
-       pix->height = rect.height / scale;
-
-       if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
-           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-               pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv; /* bpp */
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-                           ? 0 : (pix->width * pix->priv) / 8;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. Unmap the "
-                                      "buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap  || cam->io == IO_READ)
-               sn9c102_release_buffers(cam);
-
-       err += sn9c102_set_pix_format(cam, pix);
-       err += sn9c102_set_crop(cam, &rect);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, pix);
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-       err += sn9c102_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               sn9c102_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               sn9c102_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression,
-                        sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum sn9c102_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0 && jc.quality != 1)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       err += sn9c102_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open "
-                      "/dev/video%d again.", cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
-                              "still mapped.");
-                       return -EINVAL;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       sn9c102_empty_framequeues(cam);
-
-       sn9c102_release_buffers(cam);
-       if (rb.count)
-               rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               sn9c102_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
-                     void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct sn9c102_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       sn9c102_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
-               sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
-                              unsigned int cmd, void __user * arg)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return sn9c102_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return sn9c102_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return sn9c102_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return sn9c102_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return sn9c102_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return sn9c102_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-               return sn9c102_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP_OLD:
-       case VIDIOC_CROPCAP:
-               return sn9c102_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return sn9c102_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return sn9c102_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return sn9c102_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return sn9c102_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return sn9c102_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return sn9c102_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return sn9c102_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return sn9c102_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return sn9c102_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return sn9c102_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return sn9c102_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return sn9c102_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return sn9c102_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-               return sn9c102_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static int sn9c102_ioctl(struct inode* inode, struct file* filp,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "sn9c102", cmd);
-
-       err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-/*****************************************************************************/
-
-static struct file_operations sn9c102_fops = {
-       .owner = THIS_MODULE,
-       .open =    sn9c102_open,
-       .release = sn9c102_release,
-       .ioctl =   sn9c102_ioctl,
-       .read =    sn9c102_read,
-       .poll =    sn9c102_poll,
-       .mmap =    sn9c102_mmap,
-       .llseek =  no_llseek,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct sn9c102_device* cam;
-       static unsigned int dev_nr = 0;
-       unsigned int i;
-       int err = 0, r;
-
-       if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       mutex_init(&cam->dev_mutex);
-
-       r = sn9c102_read_reg(cam, 0x00);
-       if (r < 0 || r != 0x10) {
-               DBG(1, "Sorry, this is not a SN9C10x based camera "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
-               err = -ENODEV;
-               goto fail;
-       }
-
-       cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
-                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
-       switch (cam->bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               DBG(2, "SN9C10[12] PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
-               break;
-       case BRIDGE_SN9C103:
-               DBG(2, "SN9C103 PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
-               break;
-       }
-
-       for  (i = 0; sn9c102_sensor_table[i]; i++) {
-               err = sn9c102_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err) {
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-               DBG(3, "Support for %s maintained by %s",
-                   cam->sensor.name, cam->sensor.maintainer);
-       } else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (sn9c102_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
-       cam->v4ldev->fops = &sn9c102_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       mutex_lock(&cam->dev_mutex);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       sn9c102_create_sysfs(cam);
-       DBG(2, "Optional device control through 'sysfs' interface ready");
-#endif
-
-       usb_set_intfdata(intf, cam);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void sn9c102_usb_disconnect(struct usb_interface* intf)
-{
-       struct sn9c102_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
-
-       down_write(&sn9c102_disconnect);
-
-       mutex_lock(&cam->dev_mutex);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       wake_up_interruptible_all(&cam->open);
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor);
-               cam->state |= DEV_MISCONFIGURED;
-               sn9c102_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
-               cam->state |= DEV_DISCONNECTED;
-               sn9c102_release_resources(cam);
-       }
-
-       mutex_unlock(&cam->dev_mutex);
-
-       if (!cam->users)
-               kfree(cam);
-
-       up_write(&sn9c102_disconnect);
-}
-
-
-static struct usb_driver sn9c102_usb_driver = {
-       .name =       "sn9c102",
-       .id_table =   sn9c102_id_table,
-       .probe =      sn9c102_usb_probe,
-       .disconnect = sn9c102_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init sn9c102_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
-       KDBG(3, SN9C102_MODULE_AUTHOR);
-
-       if ((err = usb_register(&sn9c102_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit sn9c102_module_exit(void)
-{
-       usb_deregister(&sn9c102_usb_driver);
-}
-
-
-module_init(sn9c102_module_init);
-module_exit(sn9c102_module_exit);
diff --git a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c
deleted file mode 100644 (file)
index 46c12ec..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/***************************************************************************
- * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor hv7131d;
-
-
-static int hv7131d_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x0e, 0x18);
-       err += sn9c102_write_reg(cam, 0xf2, 0x19);
-
-       err += sn9c102_i2c_write(cam, 0x01, 0x04);
-       err += sn9c102_i2c_write(cam, 0x02, 0x00);
-       err += sn9c102_i2c_write(cam, 0x28, 0x00);
-
-       return err;
-}
-
-
-static int hv7131d_get_ctrl(struct sn9c102_device* cam, 
-                            struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = sn9c102_i2c_read(cam, 0x26),
-                           r2 = sn9c102_i2c_read(cam, 0x27);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 8) | (r2 & 0xff);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
-                       return -EIO;
-               ctrl->value = 0x3f - (ctrl->value & 0x3f);
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
-                       return -EIO;
-               ctrl->value = 0x3f - (ctrl->value & 0x3f);
-               return 0;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
-                       return -EIO;
-               ctrl->value = 0x3f - (ctrl->value & 0x3f);
-               return 0;
-       case SN9C102_V4L2_CID_RESET_LEVEL:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x3f;
-               return 0;
-       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x07;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int hv7131d_set_ctrl(struct sn9c102_device* cam, 
-                            const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
-               err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_RESET_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
-               err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int hv7131d_set_crop(struct sn9c102_device* cam, 
-                            const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &hv7131d;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int hv7131d_set_pix_format(struct sn9c102_device* cam, 
-                                  const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x42, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0xf2, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor hv7131d = {
-       .name = "HV7131D",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x11,
-       .init = &hv7131d_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x0250,
-                       .maximum = 0xffff,
-                       .step = 0x0001,
-                       .default_value = 0x0250,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x20,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x1e,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_RESET_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "reset level",
-                       .minimum = 0x19,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x30,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "pixel bias voltage",
-                       .minimum = 0x00,
-                       .maximum = 0x07,
-                       .step = 0x01,
-                       .default_value = 0x02,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &hv7131d_get_ctrl,
-       .set_ctrl = &hv7131d_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &hv7131d_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &hv7131d_set_pix_format
-};
-
-
-int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
-       r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
-       if (r0 < 0 || r1 < 0)
-               return -EIO;
-
-       if (r0 != 0x00 && r1 != 0x04)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &hv7131d);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_mi0343.c b/drivers/usb/media/sn9c102_mi0343.c
deleted file mode 100644 (file)
index d9aa7a6..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/***************************************************************************
- * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor mi0343;
-static u8 mi0343_i2c_data[5+1];
-
-
-static int mi0343_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x0a, 0x14);
-       err += sn9c102_write_reg(cam, 0x40, 0x01);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x07, 0x18);
-       err += sn9c102_write_reg(cam, 0xa0, 0x19);
-
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x0d, 0x00, 0x01, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x0d, 0x00, 0x00, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x03, 0x01, 0xe1, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x04, 0x02, 0x81, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x05, 0x00, 0x17, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x06, 0x00, 0x11, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x62, 0x04, 0x9a, 0, 0);
-
-       return err;
-}
-
-
-static int mi0343_get_ctrl(struct sn9c102_device* cam, 
-                           struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x09, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               ctrl->value = mi0343_i2c_data[2];
-               return 0;
-       case V4L2_CID_GAIN:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x35, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       case V4L2_CID_HFLIP:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x20, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
-               return 0;
-       case V4L2_CID_VFLIP:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x20, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x2d, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x2c, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x2e, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-       case V4L2_CID_RED_BALANCE:
-       case V4L2_CID_BLUE_BALANCE:
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
-               if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
-                       ctrl->value -= 0x10;
-               else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
-                       ctrl->value -= 0x60;
-               else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
-                       ctrl->value -= 0xe0;
-       }
-
-       return 0;
-}
-
-
-static int mi0343_set_ctrl(struct sn9c102_device* cam, 
-                           const struct v4l2_control* ctrl)
-{
-       u16 reg = 0;
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-       case V4L2_CID_RED_BALANCE:
-       case V4L2_CID_BLUE_BALANCE:
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if (ctrl->value <= (0x3f-0x10))
-                       reg = 0x10 + ctrl->value;
-               else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
-                       reg = 0x60 + (ctrl->value - (0x3f-0x10));
-               else
-                       reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
-               break;
-       }
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x09, ctrl->value, 0x00,
-                                                0, 0);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x35, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       case V4L2_CID_HFLIP:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x20, ctrl->value ? 0x40:0x00,
-                                                ctrl->value ? 0x20:0x00,
-                                                0, 0);
-               break;
-       case V4L2_CID_VFLIP:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x20, ctrl->value ? 0x80:0x00,
-                                                ctrl->value ? 0x80:0x00,
-                                                0, 0);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2d, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2c, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2b, reg >> 8, reg & 0xff,
-                                                0, 0);
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2e, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int mi0343_set_crop(struct sn9c102_device* cam, 
-                            const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &mi0343;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int mi0343_set_pix_format(struct sn9c102_device* cam, 
-                                 const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x0a, 0x00, 0x03, 0, 0);
-               err += sn9c102_write_reg(cam, 0x20, 0x19);
-       } else {
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x0a, 0x00, 0x05, 0, 0);
-               err += sn9c102_write_reg(cam, 0xa0, 0x19);
-       }
-
-       return err;
-}
-
-
-static struct sn9c102_sensor mi0343 = {
-       .name = "MI-0343",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x5d,
-       .init = &mi0343_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x06,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_HFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "horizontal mirror",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_VFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "vertical mirror",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &mi0343_get_ctrl,
-       .set_ctrl = &mi0343_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &mi0343_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &mi0343_set_pix_format
-};
-
-
-int sn9c102_probe_mi0343(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
-                                    2, mi0343_i2c_data) < 0)
-               return -EIO;
-
-       if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &mi0343);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c
deleted file mode 100644 (file)
index 42852b7..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/***************************************************************************
- * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor ov7630;
-
-
-static int ov7630_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x0f, 0x18);
-       err += sn9c102_write_reg(cam, 0x50, 0x19);
-
-       err += sn9c102_i2c_write(cam, 0x12, 0x80);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-       err += sn9c102_i2c_write(cam, 0x15, 0x34);
-       err += sn9c102_i2c_write(cam, 0x16, 0x03);
-       err += sn9c102_i2c_write(cam, 0x17, 0x1c);
-       err += sn9c102_i2c_write(cam, 0x18, 0xbd);
-       err += sn9c102_i2c_write(cam, 0x19, 0x06);
-       err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
-       err += sn9c102_i2c_write(cam, 0x1b, 0x04);
-       err += sn9c102_i2c_write(cam, 0x20, 0xf6);
-       err += sn9c102_i2c_write(cam, 0x23, 0xee);
-       err += sn9c102_i2c_write(cam, 0x26, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x27, 0x9a);
-       err += sn9c102_i2c_write(cam, 0x28, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x29, 0x30);
-       err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
-       err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
-       err += sn9c102_i2c_write(cam, 0x30, 0x24);
-       err += sn9c102_i2c_write(cam, 0x32, 0x86);
-       err += sn9c102_i2c_write(cam, 0x60, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x61, 0x42);
-       err += sn9c102_i2c_write(cam, 0x65, 0x00);
-       err += sn9c102_i2c_write(cam, 0x69, 0x38);
-       err += sn9c102_i2c_write(cam, 0x6f, 0x88);
-       err += sn9c102_i2c_write(cam, 0x70, 0x0b);
-       err += sn9c102_i2c_write(cam, 0x71, 0x00);
-       err += sn9c102_i2c_write(cam, 0x74, 0x21);
-       err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
-
-       return err;
-}
-
-
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
-                           const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
-               err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
-               break;
-       case V4L2_CID_CONTRAST:
-               err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
-                                                      (ctrl->value-1) | 0x20)
-                                  : sn9c102_i2c_write(cam, 0x05, 0x00);
-               break;
-       case V4L2_CID_BRIGHTNESS:
-               err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
-               break;
-       case V4L2_CID_SATURATION:
-               err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
-               break;
-       case V4L2_CID_HUE:
-               err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
-                                                      (ctrl->value-1) | 0x20)
-                                  : sn9c102_i2c_write(cam, 0x04, 0x00);
-               break;
-       case V4L2_CID_DO_WHITE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       case V4L2_CID_WHITENESS:
-               err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
-               break;
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
-               break;
-       case V4L2_CID_AUTOGAIN:
-               err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
-               break;
-       case V4L2_CID_VFLIP:
-               err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
-               break;
-       case V4L2_CID_BLACK_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_BRIGHT_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GAMMA:
-               err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
-               break;
-       case SN9C102_V4L2_CID_BAND_FILTER:
-               err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int ov7630_set_crop(struct sn9c102_device* cam,
-                           const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &ov7630;
-       int err = 0;
-       u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
-
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int ov7630_set_pix_format(struct sn9c102_device* cam,
-                                 const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x20, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0x50, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor ov7630 = {
-       .name = "OV7630",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x21,
-       .init = &ov7630_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x14,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_HUE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "hue",
-                       .minimum = 0x00,
-                       .maximum = 0x1f+1,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_SATURATION,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "saturation",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x08,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "contrast",
-                       .minimum = 0x00,
-                       .maximum = 0x1f+1,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x000,
-                       .maximum = 0x3ff,
-                       .step = 0x001,
-                       .default_value = 0x83<<2,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x3a,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x77,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BRIGHTNESS,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0xa0,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_DO_WHITE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "white balance background: blue",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x20,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_WHITENESS,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "white balance background: red",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x20,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "auto white balance",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_AUTOGAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "gain & exposure mode",
-                       .minimum = 0x00,
-                       .maximum = 0x03,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_VFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "vertical flip",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLACK_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "black pixel ratio",
-                       .minimum = 0x01,
-                       .maximum = 0x9a,
-                       .step = 0x01,
-                       .default_value = 0x8a,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "bright pixel ratio",
-                       .minimum = 0x01,
-                       .maximum = 0x9a,
-                       .step = 0x01,
-                       .default_value = 0x10,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_BAND_FILTER,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "band filter",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GAMMA,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "rgb gamma",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &ov7630_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &ov7630_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &ov7630_set_pix_format
-};
-
-
-int sn9c102_probe_ov7630(struct sn9c102_device* cam)
-{
-       const struct usb_device_id ov7630_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x602c), },
-               { USB_DEVICE(0x0c45, 0x602d), },
-               { USB_DEVICE(0x0c45, 0x608f), },
-               { USB_DEVICE(0x0c45, 0x60b0), },
-               { }
-       };
-       int err = 0;
-
-       if (!sn9c102_match_id(cam, ov7630_id_table))
-               return -ENODEV;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
-       if (err)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &ov7630);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c
deleted file mode 100644 (file)
index b1dee78..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas106b;
-
-
-static int pas106b_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x20, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x0c);
-       err += sn9c102_i2c_write(cam, 0x05, 0x5a);
-       err += sn9c102_i2c_write(cam, 0x06, 0x88);
-       err += sn9c102_i2c_write(cam, 0x07, 0x80);
-       err += sn9c102_i2c_write(cam, 0x10, 0x06);
-       err += sn9c102_i2c_write(cam, 0x11, 0x06);
-       err += sn9c102_i2c_write(cam, 0x12, 0x00);
-       err += sn9c102_i2c_write(cam, 0x14, 0x02);
-       err += sn9c102_i2c_write(cam, 0x13, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas106b_get_ctrl(struct sn9c102_device* cam, 
-                            struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = sn9c102_i2c_read(cam, 0x03),
-                           r2 = sn9c102_i2c_read(cam, 0x04);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 4) | (r2 & 0x0f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case V4L2_CID_CONTRAST:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x07;
-               return 0;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
-                       return -EIO;
-               ctrl->value = (ctrl->value & 0x1f) << 1;
-               return 0;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
-                       return -EIO;
-               ctrl->value &= 0xf8;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas106b_set_ctrl(struct sn9c102_device* cam, 
-                            const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
-               break;
-       case V4L2_CID_CONTRAST:
-               err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
-               err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x13, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas106b_set_crop(struct sn9c102_device* cam, 
-                            const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas106b;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int pas106b_set_pix_format(struct sn9c102_device* cam, 
-                                  const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x2c, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas106b = {
-       .name = "PAS106B",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas106b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x125,
-                       .maximum = 0xfff,
-                       .step = 0x001,
-                       .default_value = 0x140,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0d,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "contrast",
-                       .minimum = 0x00,
-                       .maximum = 0x07,
-                       .step = 0x01,
-                       .default_value = 0x00, /* 0x00~0x03 have same effect */
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x06,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3e,
-                       .step = 0x02,
-                       .default_value = 0x02,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &pas106b_get_ctrl,
-       .set_ctrl = &pas106b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-       },
-       .set_crop = &pas106b_set_crop,
-       .pix_format = {
-               .width = 352,
-               .height = 288,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8, /* we use this field as 'bits per pixel' */
-       },
-       .set_pix_format = &pas106b_set_pix_format
-};
-
-
-int sn9c102_probe_pas106b(struct sn9c102_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       /*
-          Minimal initialization to enable the I2C communication
-          NOTE: do NOT change the values!
-       */
-       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
-       err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
-       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
-       if (err)
-               return -EIO;
-
-       r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
-       r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
-
-       if (r0 < 0 || r1 < 0)
-               return -EIO;
-
-       pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x007)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas106b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c
deleted file mode 100644 (file)
index 3453237..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bca;
-
-
-static int pas202bca_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x30, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x14);
-       err += sn9c102_i2c_write(cam, 0x03, 0x40);
-       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
-       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x10, 0x08);
-       err += sn9c102_i2c_write(cam, 0x13, 0x63);
-       err += sn9c102_i2c_write(cam, 0x15, 0x70);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas202bca_set_pix_format(struct sn9c102_device* cam,
-                                    const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x24, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static int pas202bca_set_ctrl(struct sn9c102_device* cam,
-                              const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas202bca_set_crop(struct sn9c102_device* cam,
-                              const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas202bca;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas202bca = {
-       .name = "PAS202BCA",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas202bca_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &pas202bca_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &pas202bca_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &pas202bca_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
-{
-       const struct usb_device_id pas202bca_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x60af), },
-               { }
-       };
-       int err = 0;
-
-       if (!sn9c102_match_id(cam,pas202bca_id_table))
-               return -ENODEV;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x40, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas202bca);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c
deleted file mode 100644 (file)
index d068616..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera   *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
- *                       <medaglia@undl.org.br>                            *
- *                       http://cadu.homelinux.com:8080/                   *
- *                                                                         *
- * DAC Magnitude, exposure and green gain controls added by                *
- * Luca Risolia <luca.risolia@studio.unibo.it>                             *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x30, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x14);
-       err += sn9c102_i2c_write(cam, 0x03, 0x40);
-       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
-       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x10, 0x08);
-       err += sn9c102_i2c_write(cam, 0x13, 0x63);
-       err += sn9c102_i2c_write(cam, 0x15, 0x70);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct sn9c102_device* cam, 
-                              struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = sn9c102_i2c_read(cam, 0x04),
-                           r2 = sn9c102_i2c_read(cam, 0x05);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
-                       return -EIO;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas202bcb_set_pix_format(struct sn9c102_device* cam, 
-                                    const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x24, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static int pas202bcb_set_ctrl(struct sn9c102_device* cam, 
-                              const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas202bcb_set_crop(struct sn9c102_device* cam, 
-                              const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas202bcb;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas202bcb = {
-       .name = "PAS202BCB",
-       .maintainer = "Carlos Eduardo Medaglia Dyonisio "
-                     "<medaglia@undl.org.br>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas202bcb_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &pas202bcb_get_ctrl,
-       .set_ctrl = &pas202bcb_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &pas202bcb_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &pas202bcb_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       /*
-        *  Minimal initialization to enable the I2C communication
-        *  NOTE: do NOT change the values!
-        */
-       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
-       err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
-       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
-       if (err)
-               return -EIO;
-
-       r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
-       r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
-
-       if (r0 < 0 || r1 < 0)
-               return -EIO;
-
-       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x017)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas202bcb);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
deleted file mode 100644 (file)
index 2afd9e9..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the SN9C10x PC Camera Controllers    *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _SN9C102_SENSOR_H_
-#define _SN9C102_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct sn9c102_device;
-struct sn9c102_sensor;
-
-/*****************************************************************************/
-
-/*
-   OVERVIEW.
-   This is a small interface that allows you to add support for any CCD/CMOS
-   image sensors connected to the SN9C10X bridges. The entire API is documented
-   below. In the most general case, to support a sensor there are three steps
-   you have to follow:
-   1) define the main "sn9c102_sensor" structure by setting the basic fields;
-   2) write a probing function to be called by the core module when the USB
-      camera is recognized, then add both the USB ids and the name of that
-      function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
-      below);
-   3) implement the methods that you want/need (and fill the rest of the main
-      structure accordingly).
-   "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
-   NOT need to touch the source code of the core module for the things to work
-   properly, unless you find bugs or flaws in it. Finally, do not forget to
-   read the V4L2 API for completeness.
-*/
-
-/*****************************************************************************/
-
-/*
-   Probing functions: on success, you must attach the sensor to the camera
-   by calling sn9c102_attach_sensor() provided below.
-   To enable the I2C communication, you might need to perform a really basic
-   initialization of the SN9C10X chip by using the write function declared 
-   ahead.
-   Functions must return 0 on success, the appropriate error otherwise.
-*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
-
-/*
-   Add the above entries to this table. Be sure to add the entry in the right
-   place, since, on failure, the next probing routine is called according to 
-   the order of the list below, from top to bottom.
-*/
-#define SN9C102_SENSOR_TABLE                                                  \
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
-       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */     \
-       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
-       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
-       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
-       &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
-       &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
-       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
-       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
-       NULL,                                                                 \
-};
-
-/* Device identification */
-extern struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
-
-/* Attach a probed sensor to the camera. */
-extern void 
-sn9c102_attach_sensor(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor);
-
-/*
-   Each SN9C10x camera has proper PID/VID identifiers.
-   SN9C103 supports multiple interfaces, but we only handle the video class
-   interface.
-*/
-#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-       .idVendor = (vend),                                                   \
-       .idProduct = (prod),                                                  \
-       .bInterfaceClass = (intclass)
-
-#define SN9C102_ID_TABLE                                                      \
-static const struct usb_device_id sn9c102_id_table[] = {                      \
-       { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x6007), },                                      \
-       { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x6024), },                                      \
-       { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */      \
-       { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */                      \
-       { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */                        \
-       { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
-       { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x602d), },                                      \
-       { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
-       { }                                                                   \
-};
-
-/*****************************************************************************/
-
-/*
-   Read/write routines: they always return -1 on error, 0 or the read value
-   otherwise. NOTE that a real read operation is not supported by the SN9C10X
-   chip for some of its registers. To work around this problem, a pseudo-read
-   call is provided instead: it returns the last successfully written value 
-   on the register (0 if it has never been written), the usual -1 on error.
-*/
-
-/* The "try" I2C I/O versions are used when probing the sensor */
-extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*,
-                                 u8 address, u8 value);
-extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
-                                u8 address);
-
-/*
-   These must be used if and only if the sensor doesn't implement the standard
-   I2C protocol. There are a number of good reasons why you must use the 
-   single-byte versions of these functions: do not abuse. The first function
-   writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
-   chip. The second one programs the registers 0x09 and 0x10 with data0 and
-   data1, and places the n bytes read from the sensor register table in the
-   buffer pointed by 'buffer'. Both the functions return -1 on error; the write
-   version returns 0 on success, while the read version returns the first read
-   byte.
-*/
-extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
-                                     struct sn9c102_sensor* sensor, u8 n, 
-                                     u8 data0, u8 data1, u8 data2, u8 data3,
-                                     u8 data4, u8 data5);
-extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
-                                    struct sn9c102_sensor* sensor, u8 data0,
-                                    u8 data1, u8 n, u8 buffer[]);
-
-/* To be used after the sensor struct has been attached to the camera struct */
-extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
-extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
-
-/* I/O on registers in the bridge. Could be used by the sensor methods too */
-extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
-extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
-extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
-
-/*
-   NOTE: there are no exported debugging functions. To uniform the output you
-   must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
-   already included here, the argument being the struct device '&usbdev->dev'
-   of the sensor structure. Do NOT use these macros before the sensor is
-   attached or the kernel will crash! However, you should not need to notify
-   the user about common errors or other messages, since this is done by the
-   master module.
-*/
-
-/*****************************************************************************/
-
-enum sn9c102_i2c_sysfs_ops {
-       SN9C102_I2C_READ = 0x01,
-       SN9C102_I2C_WRITE = 0x02,
-};
-
-enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */
-       SN9C102_I2C_100KHZ = 0x01,
-       SN9C102_I2C_400KHZ = 0x02,
-};
-
-enum sn9c102_i2c_interface {
-       SN9C102_I2C_2WIRES,
-       SN9C102_I2C_3WIRES,
-};
-
-#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-
-struct sn9c102_sensor {
-       char name[32], /* sensor name */
-            maintainer[64]; /* name of the mantainer <email> */
-
-       /* Supported operations through the 'sysfs' interface */
-       enum sn9c102_i2c_sysfs_ops sysfs_ops;
-
-       /*
-          These sensor capabilities must be provided if the SN9C10X controller
-          needs to communicate through the sensor serial interface by using
-          at least one of the i2c functions available.
-       */
-       enum sn9c102_i2c_frequency frequency;
-       enum sn9c102_i2c_interface interface;
-
-       /*
-          This identifier must be provided if the image sensor implements
-          the standard I2C protocol.
-       */
-       u8 i2c_slave_id; /* reg. 0x09 */
-
-       /*
-          NOTE: Where not noted,most of the functions below are not mandatory.
-                Set to null if you do not implement them. If implemented,
-                they must return 0 on success, the proper error otherwise.
-       */
-
-       int (*init)(struct sn9c102_device* cam);
-       /*
-          This function will be called after the sensor has been attached. 
-          It should be used to initialize the sensor only, but may also
-          configure part of the SN9C10X chip if necessary. You don't need to
-          setup picture settings like brightness, contrast, etc.. here, if
-          the corrisponding controls are implemented (see below), since 
-          they are adjusted in the core driver by calling the set_ctrl()
-          method after init(), where the arguments are the default values
-          specified in the v4l2_queryctrl list of supported controls;
-          Same suggestions apply for other settings, _if_ the corresponding
-          methods are present; if not, the initialization must configure the
-          sensor according to the default configuration structures below.
-       */
-
-       struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
-       /*
-          Optional list of default controls, defined as indicated in the 
-          V4L2 API. Menu type controls are not handled by this interface.
-       */
-
-       int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct sn9c102_device* cam,
-                       const struct v4l2_control* ctrl);
-       /*
-          You must implement at least the set_ctrl method if you have defined
-          the list above. The returned value must follow the V4L2
-          specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
-          are not supported by this driver, so do not implement them. Also,
-          you don't have to check whether the passed values are out of bounds,
-          given that this is done by the core module.
-       */
-
-       struct v4l2_cropcap cropcap;
-       /*
-          Think the image sensor as a grid of R,G,B monochromatic pixels
-          disposed according to a particular Bayer pattern, which describes
-          the complete array of pixels, from (0,0) to (xmax, ymax). We will
-          use this coordinate system from now on. It is assumed the sensor
-          chip can be programmed to capture/transmit a subsection of that
-          array of pixels: we will call this subsection "active window".
-          It is not always true that the largest achievable active window can
-          cover the whole array of pixels. The V4L2 API defines another
-          area called "source rectangle", which, in turn, is a subrectangle of
-          the active window. The SN9C10X chip is always programmed to read the
-          source rectangle.
-          The bounds of both the active window and the source rectangle are
-          specified in the cropcap substructures 'bounds' and 'defrect'.
-          By default, the source rectangle should cover the largest possible
-          area. Again, it is not always true that the largest source rectangle
-          can cover the entire active window, although it is a rare case for 
-          the hardware we have. The bounds of the source rectangle _must_ be
-          multiple of 16 and must use the same coordinate system as indicated
-          before; their centers shall align initially.
-          If necessary, the sensor chip must be initialized during init() to
-          set the bounds of the active sensor window; however, by default, it
-          usually covers the largest achievable area (maxwidth x maxheight)
-          of pixels, so no particular initialization is needed, if you have
-          defined the correct default bounds in the structures.
-          See the V4L2 API for further details.
-          NOTE: once you have defined the bounds of the active window
-                (struct cropcap.bounds) you must not change them.anymore.
-          Only 'bounds' and 'defrect' fields are mandatory, other fields
-          will be ignored.
-       */
-
-       int (*set_crop)(struct sn9c102_device* cam,
-                       const struct v4l2_rect* rect);
-       /*
-          To be called on VIDIOC_C_SETCROP. The core module always calls a
-          default routine which configures the appropriate SN9C10X regs (also
-          scaling), but you may need to override/adjust specific stuff.
-          'rect' contains width and height values that are multiple of 16: in
-          case you override the default function, you always have to program
-          the chip to match those values; on error return the corresponding
-          error code without rolling back.
-          NOTE: in case, you must program the SN9C10X chip to get rid of 
-                blank pixels or blank lines at the _start_ of each line or
-                frame after each HSYNC or VSYNC, so that the image starts with
-                real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
-                V_SIZE you don't have to care about blank pixels or blank
-                lines at the end of each line or frame).
-       */
-
-       struct v4l2_pix_format pix_format;
-       /*
-          What you have to define here are: 1) initial 'width' and 'height' of
-          the target rectangle 2) the initial 'pixelformat', which can be
-          either V4L2_PIX_FMT_SN9C10X (for compressed video) or
-          V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
-          number of bits per pixel for uncompressed video, 8 or 9 (despite the
-          current value of 'pixelformat').
-          NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
-                  of cropcap.defrect.width and cropcap.defrect.height. I
-                  suggest 1/1.
-          NOTE 2: The initial compression quality is defined by the first bit
-                  of reg 0x17 during the initialization of the image sensor.
-          NOTE 3: as said above, you have to program the SN9C10X chip to get
-                  rid of any blank pixels, so that the output of the sensor
-                  matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
-       */
-
-       int (*set_pix_format)(struct sn9c102_device* cam,
-                             const struct v4l2_pix_format* pix);
-       /*
-          To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
-          SN9C10X pixel format or viceversa. On error return the corresponding
-          error code without rolling back.
-       */
-
-       /*
-          Do NOT write to the data below, it's READ ONLY. It is used by the
-          core module to store successfully updated values of the above
-          settings, for rollbacks..etc..in case of errors during atomic I/O
-       */
-       struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-/*****************************************************************************/
-
-/* Private ioctl's for control settings supported by some image sensors */
-#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
-#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
-#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
-#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
-#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
-
-#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
deleted file mode 100644 (file)
index 2e08c55..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor tas5110c1b;
-
-
-static int tas5110c1b_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x44, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x0a, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x06, 0x18);
-       err += sn9c102_write_reg(cam, 0xfb, 0x19);
-
-       err += sn9c102_i2c_write(cam, 0xc0, 0x80);
-
-       return err;
-}
-
-
-static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, 
-                               const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int tas5110c1b_set_crop(struct sn9c102_device* cam, 
-                               const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &tas5110c1b;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       /* Don't change ! */
-       err += sn9c102_write_reg(cam, 0x14, 0x1a);
-       err += sn9c102_write_reg(cam, 0x0a, 0x1b);
-       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
-
-       return err;
-}
-
-
-static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, 
-                                     const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x2b, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0xfb, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor tas5110c1b = {
-       .name = "TAS5110C1B",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_3WIRES,
-       .init = &tas5110c1b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0xf6,
-                       .step = 0x01,
-                       .default_value = 0x40,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &tas5110c1b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-       },
-       .set_crop = &tas5110c1b_set_crop,
-       .pix_format = {
-               .width = 352,
-               .height = 288,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &tas5110c1b_set_pix_format
-};
-
-
-int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
-{
-       const struct usb_device_id tas5110c1b_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x6001), },
-               { USB_DEVICE(0x0c45, 0x6005), },
-               { USB_DEVICE(0x0c45, 0x60ab), },
-               { }
-       };
-
-       /* Sensor detection is based on USB pid/vid */
-       if (!sn9c102_match_id(cam, tas5110c1b_id_table))
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &tas5110c1b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
deleted file mode 100644 (file)
index c7b3397..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor tas5130d1b;
-
-
-static int tas5130d1b_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x04, 0x01);
-       err += sn9c102_write_reg(cam, 0x01, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x07, 0x18);
-
-       return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, 
-                               const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
-               break;
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int tas5130d1b_set_crop(struct sn9c102_device* cam, 
-                               const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &tas5130d1b;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       /* Do NOT change! */
-       err += sn9c102_write_reg(cam, 0x1f, 0x1a);
-       err += sn9c102_write_reg(cam, 0x1a, 0x1b);
-       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
-
-       return err;
-}
-
-
-static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, 
-                                     const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x63, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0xf3, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor tas5130d1b = {
-       .name = "TAS5130D1B",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_3WIRES,
-       .init = &tas5130d1b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0xf6,
-                       .step = 0x02,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = 0x47,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &tas5130d1b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &tas5130d1b_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &tas5130d1b_set_pix_format
-};
-
-
-int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
-{
-       const struct usb_device_id tas5130d1b_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x6025), },
-               { USB_DEVICE(0x0c45, 0x60aa), },
-               { }
-       };
-
-       /* Sensor detection is based on USB pid/vid */
-       if (!sn9c102_match_id(cam, tas5130d1b_id_table))
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &tas5130d1b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
deleted file mode 100644 (file)
index 9636da2..0000000
+++ /dev/null
@@ -1,1508 +0,0 @@
-/*
- *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
- *  
- * Thanks to STMicroelectronics for information on the usb commands, and 
- * to Steve Miller at STM for his help and encouragement while I was 
- * writing this driver.
- *
- * This driver is based heavily on the 
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History: 
- * ver 0.1 October, 2001. Initial attempt. 
- *
- * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
- *                         function, made more stable (?)
- *
- * ver 0.21 Nov, 2001.     Added gamma correction and white balance, 
- *                         due to Alexander Schwartz. Still trying to 
- *                         improve stablility. Moved stuff into stv680.h
- *
- * ver 0.22 Nov, 2001.    Added sharpen function (by Michael Sweet, 
- *                         mike@easysw.com) from GIMP, also used in pencam. 
- *                         Simple, fast, good integer math routine.
- *
- * ver 0.23 Dec, 2001 (gkh)
- *                        Took out sharpen function, ran code through
- *                        Lindent, and did other minor tweaks to get
- *                        things to work properly with 2.5.1
- *
- * ver 0.24 Jan, 2002 (kjs) 
- *                         Fixed the problem with webcam crashing after
- *                         two pictures. Changed the way pic is halved to 
- *                         improve quality. Got rid of green line around 
- *                         frame. Fix brightness reset when changing size 
- *                         bug. Adjusted gamma filters slightly.
- *
- * ver 0.25 Jan, 2002 (kjs)
- *                        Fixed a bug in which the driver sometimes attempted
- *                        to set to a non-supported size. This allowed
- *                        gnomemeeting to work.
- *                        Fixed proc entry removal bug.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/errno.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#include "stv680.h"
-
-static int video_nr = -1;
-static int swapRGB = 0;   /* default for auto sleect */
-static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
-
-static unsigned int debug = 0;
-
-#define PDEBUG(level, fmt, args...) \
-       do { \
-       if (debug >= level)     \
-               info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \
-       } while (0)
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.25"
-#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
-#define DRIVER_DESC "STV0680 USB Camera Driver"
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (debug, "Debug enabled or not");
-module_param(swapRGB_on, int, 0);
-MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
-module_param(video_nr, int, 0);
-
-/********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
- ********************************************************************/
-static void *rvmalloc (unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32 (size);
-       if (!mem)
-               return NULL;
-
-       memset (mem, 0, size);  /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       return mem;
-}
-
-static void rvfree (void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree (mem);
-}
-
-
-/*********************************************************************
- * pencam read/write functions
- ********************************************************************/
-
-static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
-{
-       int ret = -1;
-
-       switch (set) {
-       case 0:         /*  0xc1  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_rcvctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 1:         /*  0x41  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_sndctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 2:         /*  0x80  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_rcvctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_IN | USB_RECIP_DEVICE),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 3:         /*  0x40  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_sndctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       }
-       if ((ret < 0) && (req != 0x0a)) {
-               PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
-       }
-       return ret;
-}
-
-static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
-{
-
-       if (configuration != dev->udev->actconfig->desc.bConfigurationValue
-                       || usb_reset_configuration (dev->udev) < 0) {
-               PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
-               return -1;
-       }
-       if (usb_set_interface (dev->udev, interface, alternate) < 0) {
-               PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
-               return -1;
-       }
-       return 0;
-}
-
-static int stv_stop_video (struct usb_stv *dev)
-{
-       int i;
-       unsigned char *buf;
-
-       buf = kmalloc (40, GFP_KERNEL);
-       if (buf == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-
-       /* this is a high priority command; it stops all lower order commands */
-       if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
-               i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);   /* Get Last Error; 2 = busy */
-               PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
-       } else {
-               PDEBUG (1, "STV(i): Camera reset to idle mode.");
-       }
-
-       if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
-               PDEBUG (1, "STV(e): Reset config during exit failed");
-
-       /*  get current mode  */
-       buf[0] = 0xf0;
-       if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)     /* get mode */
-               PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
-       if (dev->origMode != buf[0]) {
-               memset (buf, 0, 8);
-               buf[0] = (unsigned char) dev->origMode;
-               if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
-                       PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
-                       i = -1;
-               }
-               buf[0] = 0xf0;
-               i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
-               if ((i != 0x08) || (buf[0] != dev->origMode)) {
-                       PDEBUG (0, "STV(e): camera NOT set to original resolution.");
-                       i = -1;
-               } else
-                       PDEBUG (0, "STV(i): Camera set to original resolution");
-       }
-       /* origMode */
-       kfree(buf);
-       return i;
-}
-
-static int stv_set_video_mode (struct usb_stv *dev)
-{
-       int i, stop_video = 1;
-       unsigned char *buf;
-
-       buf = kmalloc (40, GFP_KERNEL);
-       if (buf == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-
-       if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
-               kfree(buf);
-               return i;
-       }
-
-       i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
-       if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
-               PDEBUG (1, "STV(e): Could not get descriptor 0100.");
-               goto error;
-       }
-
-       /*  set alternate interface 1 */
-       if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
-               goto error;
-
-       if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
-               goto error;
-       PDEBUG (1, "STV(i): Setting video mode.");
-       /*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
-       if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
-               stop_video = 0;
-               goto error;
-       }
-       goto exit;
-
-error:
-       kfree(buf);
-       if (stop_video == 1)
-               stv_stop_video (dev);
-       return -1;
-
-exit:
-       kfree(buf);
-       return 0;
-}
-
-static int stv_init (struct usb_stv *stv680)
-{
-       int i = 0;
-       unsigned char *buffer;
-       unsigned long int bufsize;
-
-       buffer = kzalloc (40, GFP_KERNEL);
-       if (buffer == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-       udelay (100);
-
-       /* set config 1, interface 0, alternate 0 */
-       if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
-               kfree(buffer);
-               PDEBUG (0, "STV(e): set config 1,0,0 failed");
-               return -1;
-       }
-       /* ping camera to be sure STV0680 is present */
-       if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
-               goto error;
-       if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
-               PDEBUG (1, "STV(e): camera ping failed!!");
-               goto error;
-       }
-
-       /* get camera descriptor */
-       if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
-               goto error;
-       i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
-       if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
-               PDEBUG (1, "STV(e): Could not get descriptor 0200.");
-               goto error;
-       }
-       if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-               goto error;
-
-       stv680->SupportedModes = buffer[7];
-       i = stv680->SupportedModes;
-       stv680->CIF = 0;
-       stv680->VGA = 0;
-       stv680->QVGA = 0;
-       if (i & 1)
-               stv680->CIF = 1;
-       if (i & 2)
-               stv680->VGA = 1;
-       if (i & 8)
-               stv680->QVGA = 1;
-       if (stv680->SupportedModes == 0) {
-               PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
-               i = -1;
-               goto error;
-       } else {
-               if (stv680->CIF)
-                       PDEBUG (0, "STV(i): CIF is supported");
-               if (stv680->QVGA)
-                       PDEBUG (0, "STV(i): QVGA is supported");
-       }
-       /* FW rev, ASIC rev, sensor ID  */
-       PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
-       PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
-       PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
-
-       /*  set alternate interface 1 */
-       if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
-               goto error;
-
-       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
-               goto error;
-       i = buffer[3];
-       PDEBUG (0, "STV(i): Camera has %i pictures.", i);
-
-       /*  get current mode */
-       if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
-               goto error;
-       stv680->origMode = buffer[0];   /* 01 = VGA, 03 = QVGA, 00 = CIF */
-
-       /* This will attemp CIF mode, if supported. If not, set to QVGA  */
-       memset (buffer, 0, 8);
-       if (stv680->CIF)
-               buffer[0] = 0x00;
-       else if (stv680->QVGA)
-               buffer[0] = 0x03;
-       if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
-               PDEBUG (0, "STV(i): Set_Camera_Mode failed");
-               i = -1;
-               goto error;
-       }
-       buffer[0] = 0xf0;
-       stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
-       if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
-               PDEBUG (0, "STV(e): Error setting camera video mode!");
-               i = -1;
-               goto error;
-       } else {
-               if (buffer[0] == 0) {
-                       stv680->VideoMode = 0x0000;
-                       PDEBUG (0, "STV(i): Video Mode set to CIF");
-               }
-               if (buffer[0] == 0x03) {
-                       stv680->VideoMode = 0x0300;
-                       PDEBUG (0, "STV(i): Video Mode set to QVGA");
-               }
-       }
-       if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
-               goto error;
-       bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
-       stv680->cwidth = (buffer[4] << 8) | (buffer[5]);        /* ->camera = 322, 356, 644  */
-       stv680->cheight = (buffer[6] << 8) | (buffer[7]);       /* ->camera = 242, 292, 484  */
-       stv680->origGain = buffer[12];
-
-       goto exit;
-
-error:
-       i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);     /* Get Last Error */
-       PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
-       kfree(buffer);
-       return -1;
-
-exit:
-       kfree(buffer);
-
-       /* video = 320x240, 352x288 */
-       if (stv680->CIF == 1) {
-               stv680->maxwidth = 352;
-               stv680->maxheight = 288;
-               stv680->vwidth = 352;
-               stv680->vheight = 288;
-       }
-       if (stv680->QVGA == 1) {
-               stv680->maxwidth = 320;
-               stv680->maxheight = 240;
-               stv680->vwidth = 320;
-               stv680->vheight = 240;
-       }
-
-       stv680->rawbufsize = bufsize;   /* must be ./. by 8 */
-       stv680->maxframesize = bufsize * 3;     /* RGB size */
-       PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
-       PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
-
-       /* some default values */
-       stv680->bulk_in_endpointAddr = 0x82;
-       stv680->dropped = 0;
-       stv680->error = 0;
-       stv680->framecount = 0;
-       stv680->readcount = 0;
-       stv680->streaming = 0;
-       /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
-       stv680->brightness = 32767;
-       stv680->chgbright = 0;
-       stv680->whiteness = 0;  /* only for greyscale */
-       stv680->colour = 32767;
-       stv680->contrast = 32767;
-       stv680->hue = 32767;
-       stv680->palette = STV_VIDEO_PALETTE;
-       stv680->depth = 24;     /* rgb24 bits */
-       if ((swapRGB_on == 0) && (swapRGB == 0))
-               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
-       else if ((swapRGB_on == 0) && (swapRGB == 1))
-               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
-       else if (swapRGB_on == 1)
-               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
-       else if (swapRGB_on == -1)
-               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
-       
-       if (stv_set_video_mode (stv680) < 0) {
-               PDEBUG (0, "STV(e): Could not set video mode in stv_init");
-               return -1;
-       }
-
-       return 0;
-}
-
-/***************** last of pencam  routines  *******************/
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-#define stv680_file(name, variable, field)                             \
-static ssize_t show_##name(struct class_device *class_dev, char *buf)  \
-{                                                                      \
-       struct video_device *vdev = to_video_device(class_dev);         \
-       struct usb_stv *stv = video_get_drvdata(vdev);                  \
-       return sprintf(buf, field, stv->variable);                      \
-}                                                                      \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-stv680_file(model, camera_name, "%s\n");
-stv680_file(in_use, user, "%d\n");
-stv680_file(streaming, streaming, "%d\n");
-stv680_file(palette, palette, "%i\n");
-stv680_file(frames_total, readcount, "%d\n");
-stv680_file(frames_read, framecount, "%d\n");
-stv680_file(packets_dropped, dropped, "%d\n");
-stv680_file(decoding_errors, error, "%d\n");
-
-static void stv680_create_sysfs_files(struct video_device *vdev)
-{
-       video_device_create_file(vdev, &class_device_attr_model);
-       video_device_create_file(vdev, &class_device_attr_in_use);
-       video_device_create_file(vdev, &class_device_attr_streaming);
-       video_device_create_file(vdev, &class_device_attr_palette);
-       video_device_create_file(vdev, &class_device_attr_frames_total);
-       video_device_create_file(vdev, &class_device_attr_frames_read);
-       video_device_create_file(vdev, &class_device_attr_packets_dropped);
-       video_device_create_file(vdev, &class_device_attr_decoding_errors);
-}
-
-static void stv680_remove_sysfs_files(struct video_device *vdev)
-{
-       video_device_remove_file(vdev, &class_device_attr_model);
-       video_device_remove_file(vdev, &class_device_attr_in_use);
-       video_device_remove_file(vdev, &class_device_attr_streaming);
-       video_device_remove_file(vdev, &class_device_attr_palette);
-       video_device_remove_file(vdev, &class_device_attr_frames_total);
-       video_device_remove_file(vdev, &class_device_attr_frames_read);
-       video_device_remove_file(vdev, &class_device_attr_packets_dropped);
-       video_device_remove_file(vdev, &class_device_attr_decoding_errors);
-}
-
-/********************************************************************
- * Camera control
- *******************************************************************/
-
-static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-       /* This sets values for v4l interface. max/min = 65535/0  */
-
-       p->brightness = stv680->brightness;
-       p->whiteness = stv680->whiteness;       /* greyscale */
-       p->colour = stv680->colour;
-       p->contrast = stv680->contrast;
-       p->hue = stv680->hue;
-       p->palette = stv680->palette;
-       p->depth = stv680->depth;
-       return 0;
-}
-
-static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-       /* See above stv680_get_pict  */
-
-       if (p->palette != STV_VIDEO_PALETTE) {
-               PDEBUG (2, "STV(e): Palette set error in _set_pic");
-               return 1;
-       }
-
-       if (stv680->brightness != p->brightness) {
-               stv680->chgbright = 1;
-               stv680->brightness = p->brightness;
-       } 
-
-       stv680->whiteness = p->whiteness;       /* greyscale */
-       stv680->colour = p->colour;
-       stv680->contrast = p->contrast;
-       stv680->hue = p->hue;
-       stv680->palette = p->palette;
-       stv680->depth = p->depth;
-
-       return 0;
-}
-
-static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_stv *stv680 = urb->context;
-       int length = urb->actual_length;
-
-       if (length < stv680->rawbufsize)
-               PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
-
-       /* ohoh... */
-       if (!stv680->streaming)
-               return;
-
-       if (!stv680->udev) {
-               PDEBUG (0, "STV(e): device vapourished in video_irq");
-               return;
-       }
-
-       /* 0 sized packets happen if we are to fast, but sometimes the camera
-          keeps sending them forever...
-        */
-       if (length && !urb->status) {
-               stv680->nullpackets = 0;
-               switch (stv680->scratch[stv680->scratch_next].state) {
-               case BUFFER_READY:
-               case BUFFER_BUSY:
-                       stv680->dropped++;
-                       break;
-
-               case BUFFER_UNUSED:
-                       memcpy (stv680->scratch[stv680->scratch_next].data,
-                               (unsigned char *) urb->transfer_buffer, length);
-                       stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
-                       stv680->scratch[stv680->scratch_next].length = length;
-                       if (waitqueue_active (&stv680->wq)) {
-                               wake_up_interruptible (&stv680->wq);
-                       }
-                       stv680->scratch_overflow = 0;
-                       stv680->scratch_next++;
-                       if (stv680->scratch_next >= STV680_NUMSCRATCH)
-                               stv680->scratch_next = 0;
-                       break;
-               }               /* switch  */
-       } else {
-               stv680->nullpackets++;
-               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-                       if (waitqueue_active (&stv680->wq)) {
-                               wake_up_interruptible (&stv680->wq);
-                       }
-               }
-       }                       /*  if - else */
-
-       /* Resubmit urb for new data */
-       urb->status = 0;
-       urb->dev = stv680->udev;
-       if (usb_submit_urb (urb, GFP_ATOMIC))
-               PDEBUG (0, "STV(e): urb burned down in video irq");
-       return;
-}                              /*  _video_irq  */
-
-static int stv680_start_stream (struct usb_stv *stv680)
-{
-       struct urb *urb;
-       int err = 0, i;
-
-       stv680->streaming = 1;
-
-       /* Do some memory allocation */
-       for (i = 0; i < STV680_NUMFRAMES; i++) {
-               stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
-               stv680->frame[i].curpix = 0;
-       }
-       /* packet size = 4096  */
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-               if (stv680->sbuf[i].data == NULL) {
-                       PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
-                       return -1;
-               }
-       }
-
-       stv680->scratch_next = 0;
-       stv680->scratch_use = 0;
-       stv680->scratch_overflow = 0;
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-               if (stv680->scratch[i].data == NULL) {
-                       PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
-                       return -1;
-               }
-               stv680->scratch[i].state = BUFFER_UNUSED;
-       }
-
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               urb = usb_alloc_urb (0, GFP_KERNEL);
-               if (!urb)
-                       return -ENOMEM;
-
-               /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
-               usb_fill_bulk_urb (urb, stv680->udev,
-                                  usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
-                                  stv680->sbuf[i].data, stv680->rawbufsize,
-                                  stv680_video_irq, stv680);
-               stv680->urb[i] = urb;
-               err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-               if (err)
-                       PDEBUG (0, "STV(e): urb burned down in start stream");
-       }                       /* i STV680_NUMSBUF */
-
-       stv680->framecount = 0;
-       return 0;
-}
-
-static int stv680_stop_stream (struct usb_stv *stv680)
-{
-       int i;
-
-       if (!stv680->streaming || !stv680->udev)
-               return 1;
-
-       stv680->streaming = 0;
-
-       for (i = 0; i < STV680_NUMSBUF; i++)
-               if (stv680->urb[i]) {
-                       usb_kill_urb (stv680->urb[i]);
-                       usb_free_urb (stv680->urb[i]);
-                       stv680->urb[i] = NULL;
-                       kfree(stv680->sbuf[i].data);
-               }
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               kfree(stv680->scratch[i].data);
-               stv680->scratch[i].data = NULL;
-       }
-
-       return 0;
-}
-
-static int stv680_set_size (struct usb_stv *stv680, int width, int height)
-{
-       int wasstreaming = stv680->streaming;
-
-       /* Check to see if we need to change */
-       if ((stv680->vwidth == width) && (stv680->vheight == height))
-               return 0;
-
-       PDEBUG (1, "STV(i): size request for %i x %i", width, height);
-       /* Check for a valid mode */
-       if ((!width || !height) || ((width & 1) || (height & 1))) {
-               PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-               return 1;
-       }
-
-       if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
-               width = stv680->maxwidth / 2;
-               height = stv680->maxheight / 2;
-       } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
-               width = 160;
-               height = 120;
-       } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
-               width = 176;
-               height = 144;
-       } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
-               width = 320;
-               height = 240;
-       } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
-               width = 352;
-               height = 288;
-       } else {
-               PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-               return 1;
-       }
-       
-       /* Stop a current stream and start it again at the new size */
-       if (wasstreaming)
-               stv680_stop_stream (stv680);
-       stv680->vwidth = width;
-       stv680->vheight = height;
-       PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
-       if (wasstreaming)
-               stv680_start_stream (stv680);
-
-       return 0;
-}
-
-/**********************************************************************
- * Video Decoding
- **********************************************************************/
-
-/*******  routines from the pencam program; hey, they work!  ********/
-
-/*
- * STV0680 Vision Camera Chipset Driver
- * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
-*/
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define AD(x, y, w) (((y)*(w)+(x))*3)
-
-static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
-{
-       int x, y, i;
-       int w = stv680->cwidth;
-       int vw = stv680->cwidth, vh = stv680->cheight;
-       unsigned int p = 0;
-       int colour = 0, bayer = 0;
-       unsigned char *raw = buffer->data;
-       struct stv680_frame *frame = &stv680->frame[stv680->curframe];
-       unsigned char *output = frame->data;
-       unsigned char *temp = frame->data;
-       int offset = buffer->offset;
-
-       if (frame->curpix == 0) {
-               if (frame->grabstate == FRAME_READY) {
-                       frame->grabstate = FRAME_GRABBING;
-               }
-       }
-       if (offset != frame->curpix) {  /* Regard frame as lost :( */
-               frame->curpix = 0;
-               stv680->error++;
-               return;
-       }
-
-       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
-               vw = 320;
-               vh = 240;
-       }
-       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
-               vw = 352;
-               vh = 288;
-       }
-
-       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
-
-       for (y = 0; y < vh; y++) {
-               for (x = 0; x < vw; x++) {
-                       if (x & 1)
-                               p = *(raw + y * w + (x >> 1));
-                       else
-                               p = *(raw + y * w + (x >> 1) + (w >> 1));
-
-                       if (y & 1)
-                               bayer = 2;
-                       else
-                               bayer = 0;
-                       if (x & 1)
-                               bayer++;
-
-                       switch (bayer) {
-                       case 0:
-                       case 3:
-                               colour = 1;
-                               break;
-                       case 1:
-                               colour = 0;
-                               break;
-                       case 2:
-                               colour = 2;
-                               break;
-                       }
-                       i = (y * vw + x) * 3;   
-                       *(output + i + colour) = (unsigned char) p;
-               }               /* for x */
-
-       }                       /* for y */
-
-       /****** gamma correction plus hardcoded white balance */
-       /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
-          Correction values red[], green[], blue[], are generated by 
-          (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
-          White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
-          converted to unsigned char. Values are in stv680.h  */
-
-       for (y = 0; y < vh; y++) {
-               for (x = 0; x < vw; x++) {
-                       i = (y * vw + x) * 3;
-                       *(output + i) = red[*(output + i)];
-                       *(output + i + 1) = green[*(output + i + 1)];
-                       *(output + i + 2) = blue[*(output + i + 2)];
-               }
-       }
-
-       /******  bayer demosaic  ******/
-       for (y = 1; y < (vh - 1); y++) {
-               for (x = 1; x < (vw - 1); x++) {        /* work out pixel type */
-                       if (y & 1)
-                               bayer = 0;
-                       else
-                               bayer = 2;
-                       if (!(x & 1))
-                               bayer++;
-
-                       switch (bayer) {
-                       case 0: /* green. blue lr, red tb */
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
-                               break;
-
-                       case 1: /* blue. green lrtb, red diagonals */
-                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
-                               break;
-
-                       case 2: /* red. green lrtb, blue diagonals */
-                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
-                               break;
-
-                       case 3: /* green. red lr, blue tb */
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
-                               break;
-                       }       /* switch */
-               }               /* for x */
-       }                       /* for y  - end demosaic  */
-
-       /* fix top and bottom row, left and right side */
-       i = vw * 3;
-       memcpy (output, (output + i), i);
-       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
-       for (y = 0; y < vh; y++) {
-               i = y * vw * 3;
-               memcpy ((output + i), (output + i + 3), 3);
-               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
-       }
-
-       /*  process all raw data, then trim to size if necessary */
-       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
-               i = 0;
-               for (y = 0; y < vh; y++) {
-                       if (!(y & 1)) {
-                               for (x = 0; x < vw; x++) {
-                                       p = (y * vw + x) * 3;
-                                       if (!(x & 1)) {
-                                               *(output + i) = *(output + p);
-                                               *(output + i + 1) = *(output + p + 1);
-                                               *(output + i + 2) = *(output + p + 2);
-                                               i += 3;
-                                       }
-                               }  /* for x */
-                       }
-               }  /* for y */
-       }
-       /* reset to proper width */
-       if ((stv680->vwidth == 160)) {
-               vw = 160;
-               vh = 120;
-       }
-       if ((stv680->vwidth == 176)) {
-               vw = 176;
-               vh = 144;
-       }
-
-       /* output is RGB; some programs want BGR  */
-       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
-       /* swapRGB_on=-1, never swap */
-       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
-               for (y = 0; y < vh; y++) {
-                       for (x = 0; x < vw; x++) {
-                               i = (y * vw + x) * 3;
-                               *(temp) = *(output + i);
-                               *(output + i) = *(output + i + 2);
-                               *(output + i + 2) = *(temp);
-                       }
-               }
-       }
-       /* brightness */
-       if (stv680->chgbright == 1) {
-               if (stv680->brightness >= 32767) {
-                       p = (stv680->brightness - 32767) / 256;
-                       for (x = 0; x < (vw * vh * 3); x++) {
-                               if ((*(output + x) + (unsigned char) p) > 255)
-                                       *(output + x) = 255;
-                               else
-                                       *(output + x) += (unsigned char) p;
-                       }       /* for */
-               } else {
-                       p = (32767 - stv680->brightness) / 256;
-                       for (x = 0; x < (vw * vh * 3); x++) {
-                               if ((unsigned char) p > *(output + x))
-                                       *(output + x) = 0;
-                               else
-                                       *(output + x) -= (unsigned char) p;
-                       }       /* for */
-               }               /* else */
-       }
-       /* if */
-       frame->curpix = 0;
-       frame->curlinepix = 0;
-       frame->grabstate = FRAME_DONE;
-       stv680->framecount++;
-       stv680->readcount++;
-       if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
-               stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
-       }
-
-}                              /* bayer_unshuffle */
-
-/*******  end routines from the pencam program  *********/
-
-static int stv680_newframe (struct usb_stv *stv680, int framenr)
-{
-       int errors = 0;
-
-       while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
-               if (!stv680->frame[framenr].curpix) {
-                       errors++;
-               }
-               wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
-
-               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-                       stv680->nullpackets = 0;
-                       PDEBUG (2, "STV(i): too many null length packets, restarting capture");
-                       stv680_stop_stream (stv680);
-                       stv680_start_stream (stv680);
-               } else {
-                       if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
-                               stv680->frame[framenr].grabstate = FRAME_ERROR;
-                               PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
-                               return -EIO;
-                       }
-                       stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
-
-                       bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
-
-                       stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
-                       stv680->scratch_use++;
-                       if (stv680->scratch_use >= STV680_NUMSCRATCH)
-                               stv680->scratch_use = 0;
-                       if (errors > STV680_MAX_ERRORS) {
-                               errors = 0;
-                               PDEBUG (2, "STV(i): too many errors, restarting capture");
-                               stv680_stop_stream (stv680);
-                               stv680_start_stream (stv680);
-                       }
-               }               /* else */
-       }                       /* while */
-       return 0;
-}
-
-/*********************************************************************
- * Video4Linux
- *********************************************************************/
-
-static int stv_open (struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       int err = 0;
-
-       /* we are called with the BKL held */
-       stv680->user = 1;
-       err = stv_init (stv680);        /* main initialization routine for camera */
-
-       if (err >= 0) {
-               stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
-               if (!stv680->fbuf) {
-                       PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
-                       err = -ENOMEM;
-               }
-               file->private_data = dev;
-       }
-       if (err)
-               stv680->user = 0;
-
-       return err;
-}
-
-static int stv_close (struct inode *inode, struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       int i;
-
-       for (i = 0; i < STV680_NUMFRAMES; i++)
-               stv680->frame[i].grabstate = FRAME_UNUSED;
-       if (stv680->streaming)
-               stv680_stop_stream (stv680);
-
-       if ((i = stv_stop_video (stv680)) < 0)
-               PDEBUG (1, "STV(e): stop_video failed in stv_close");
-
-       rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
-       stv680->user = 0;
-
-       if (stv680->removed) {
-               kfree(stv680);
-               stv680 = NULL;
-               PDEBUG (0, "STV(i): device unregistered");
-       }
-       file->private_data = NULL;
-       return 0;
-}
-
-static int stv680_do_ioctl (struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(vdev);
-
-       if (!stv680->udev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:{
-                       struct video_capability *b = arg;
-
-                       strcpy (b->name, stv680->camera_name);
-                       b->type = VID_TYPE_CAPTURE;
-                       b->channels = 1;
-                       b->audios = 0;
-                       b->maxwidth = stv680->maxwidth;
-                       b->maxheight = stv680->maxheight;
-                       b->minwidth = stv680->maxwidth / 2;
-                       b->minheight = stv680->maxheight / 2;
-                       return 0;
-               }
-       case VIDIOCGCHAN:{
-                       struct video_channel *v = arg;
-
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       v->flags = 0;
-                       v->tuners = 0;
-                       v->type = VIDEO_TYPE_CAMERA;
-                       strcpy (v->name, "STV Camera");
-                       return 0;
-               }
-       case VIDIOCSCHAN:{
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-       case VIDIOCGPICT:{
-                       struct video_picture *p = arg;
-
-                       stv680_get_pict (stv680, p);
-                       return 0;
-               }
-       case VIDIOCSPICT:{
-                       struct video_picture *p = arg;
-
-                       if (stv680_set_pict (stv680, p))
-                               return -EINVAL;
-                       return 0;
-               }
-       case VIDIOCSWIN:{
-                       struct video_window *vw = arg;
-
-                       if (vw->flags)
-                               return -EINVAL;
-                       if (vw->clipcount)
-                               return -EINVAL;
-                       if (vw->width != stv680->vwidth) {
-                               if (stv680_set_size (stv680, vw->width, vw->height)) {
-                                       PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
-                                       return -EINVAL;
-                               }
-                       }
-                       return 0;
-               }
-       case VIDIOCGWIN:{
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;      /* FIXME */
-                       vw->y = 0;
-                       vw->chromakey = 0;
-                       vw->flags = 0;
-                       vw->clipcount = 0;
-                       vw->width = stv680->vwidth;
-                       vw->height = stv680->vheight;
-                       return 0;
-               }
-       case VIDIOCGMBUF:{
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset (vm, 0, sizeof (*vm));
-                       vm->size = STV680_NUMFRAMES * stv680->maxframesize;
-                       vm->frames = STV680_NUMFRAMES;
-                       for (i = 0; i < STV680_NUMFRAMES; i++)
-                               vm->offsets[i] = stv680->maxframesize * i;
-                       return 0;
-               }
-       case VIDIOCMCAPTURE:{
-                       struct video_mmap *vm = arg;
-
-                       if (vm->format != STV_VIDEO_PALETTE) {
-                               PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
-                                       vm->format, STV_VIDEO_PALETTE);
-                               if ((vm->format == 3) && (swapRGB_on == 0))  {
-                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
-                                       /* this may fix those apps (e.g., xawtv) that want BGR */
-                                       swapRGB = 1;
-                               }
-                               return -EINVAL;
-                       }
-                       if (vm->frame >= STV680_NUMFRAMES) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
-                               return -EINVAL;
-                       }
-                       if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
-                           || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
-                                       stv680->frame[vm->frame].grabstate);
-                               return -EBUSY;
-                       }
-                       /* Is this according to the v4l spec??? */
-                       if (stv680->vwidth != vm->width) {
-                               if (stv680_set_size (stv680, vm->width, vm->height)) {
-                                       PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
-                                       return -EINVAL;
-                               }
-                       }
-                       stv680->frame[vm->frame].grabstate = FRAME_READY;
-
-                       if (!stv680->streaming)
-                               stv680_start_stream (stv680);
-
-                       return 0;
-               }
-       case VIDIOCSYNC:{
-                       int *frame = arg;
-                       int ret = 0;
-
-                       if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
-                               PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
-                               return -EINVAL;
-                       }
-                       ret = stv680_newframe (stv680, *frame);
-                       stv680->frame[*frame].grabstate = FRAME_UNUSED;
-                       return ret;
-               }
-       case VIDIOCGFBUF:{
-                       struct video_buffer *vb = arg;
-
-                       memset (vb, 0, sizeof (*vb));
-                       return 0;
-               }
-       case VIDIOCKEY:
-               return 0;
-       case VIDIOCCAPTURE:
-               {
-                       PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
-                       return -EINVAL;
-               }
-       case VIDIOCSFBUF:
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-       default:
-               return -ENOIOCTLCMD;
-       }                       /* end switch */
-
-       return 0;
-}
-
-static int stv680_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl);
-}
-
-static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       mutex_lock(&stv680->lock);
-
-       if (stv680->udev == NULL) {
-               mutex_unlock(&stv680->lock);
-               return -EIO;
-       }
-       if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
-                   & ~(PAGE_SIZE - 1))) {
-               mutex_unlock(&stv680->lock);
-               return -EINVAL;
-       }
-       pos = (unsigned long) stv680->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&stv680->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       mutex_unlock(&stv680->lock);
-
-       return 0;
-}
-
-static ssize_t stv680_read (struct file *file, char __user *buf,
-                       size_t count, loff_t *ppos)
-{
-       struct video_device *dev = file->private_data;
-       unsigned long int realcount = count;
-       int ret = 0;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       unsigned long int i;
-
-       if (STV680_NUMFRAMES != 2) {
-               PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
-               return -1;
-       }
-       if (stv680->udev == NULL)
-               return -EIO;
-       if (realcount > (stv680->vwidth * stv680->vheight * 3))
-               realcount = stv680->vwidth * stv680->vheight * 3;
-
-       /* Shouldn't happen: */
-       if (stv680->frame[0].grabstate == FRAME_GRABBING) {
-               PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
-               return -EBUSY;
-       }
-       stv680->frame[0].grabstate = FRAME_READY;
-       stv680->frame[1].grabstate = FRAME_UNUSED;
-       stv680->curframe = 0;
-
-       if (!stv680->streaming)
-               stv680_start_stream (stv680);
-
-       if (!stv680->streaming) {
-               ret = stv680_newframe (stv680, 0);      /* ret should = 0 */
-       }
-
-       ret = stv680_newframe (stv680, 0);
-
-       if (!ret) {
-               if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
-                       PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
-                       return -EFAULT;
-               }
-       } else {
-               realcount = ret;
-       }
-       stv680->frame[0].grabstate = FRAME_UNUSED;
-       return realcount;
-}                              /* stv680_read */
-
-static struct file_operations stv680_fops = {
-       .owner =        THIS_MODULE,
-       .open =         stv_open,
-       .release =      stv_close,
-       .read =         stv680_read,
-       .mmap =         stv680_mmap,
-       .ioctl =        stv680_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-static struct video_device stv680_template = {
-       .owner =        THIS_MODULE,
-       .name =         "STV0680 USB camera",
-       .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_SE401,
-       .fops =         &stv680_fops,
-       .release =      video_device_release,
-       .minor =        -1,
-};
-
-static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_host_interface *interface;
-       struct usb_stv *stv680 = NULL;
-       char *camera_name = NULL;
-       int retval = 0;
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1) {
-               PDEBUG (0, "STV(e): Number of Configurations != 1");
-               return -ENODEV;
-       }
-
-       interface = &intf->altsetting[0];
-       /* Is it a STV680? */
-       if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
-           (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
-               camera_name = "STV0680";
-               PDEBUG (0, "STV(i): STV0680 camera found.");
-       } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
-                  (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
-               camera_name = "Creative WebCam Go Mini";
-               PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
-       } else {
-               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
-               PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
-               retval = -ENODEV;
-               goto error;
-       }
-       /* We found one */
-       if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
-               PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
-               retval = -ENOMEM;
-               goto error;
-       }
-
-       stv680->udev = dev;
-       stv680->camera_name = camera_name;
-
-       stv680->vdev = video_device_alloc();
-       if (!stv680->vdev) {
-               retval = -ENOMEM;
-               goto error;
-       }
-       memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
-       stv680->vdev->dev = &intf->dev;
-       video_set_drvdata(stv680->vdev, stv680);
-
-       memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
-       init_waitqueue_head (&stv680->wq);
-       mutex_init (&stv680->lock);
-       wmb ();
-
-       if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               PDEBUG (0, "STV(e): video_register_device failed");
-               retval = -EIO;
-               goto error_vdev;
-       }
-       PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
-
-       usb_set_intfdata (intf, stv680);
-       stv680_create_sysfs_files(stv680->vdev);
-       return 0;
-
-error_vdev:
-       video_device_release(stv680->vdev);
-error:
-       kfree(stv680);
-       return retval;
-}
-
-static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
-{
-       int i;
-
-       stv680->udev = NULL;
-       stv680->frame[0].grabstate = FRAME_ERROR;
-       stv680->frame[1].grabstate = FRAME_ERROR;
-       stv680->streaming = 0;
-
-       wake_up_interruptible (&stv680->wq);
-
-       for (i = 0; i < STV680_NUMSBUF; i++)
-               if (stv680->urb[i]) {
-                       usb_kill_urb (stv680->urb[i]);
-                       usb_free_urb (stv680->urb[i]);
-                       stv680->urb[i] = NULL;
-                       kfree(stv680->sbuf[i].data);
-               }
-       for (i = 0; i < STV680_NUMSCRATCH; i++)
-               kfree(stv680->scratch[i].data);
-       PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
-
-       /* Free the memory */
-       kfree(stv680);
-}
-
-static void stv680_disconnect (struct usb_interface *intf)
-{
-       struct usb_stv *stv680 = usb_get_intfdata (intf);
-
-       usb_set_intfdata (intf, NULL);
-
-       if (stv680) {
-               /* We don't want people trying to open up the device */
-               if (stv680->vdev) {
-                       stv680_remove_sysfs_files(stv680->vdev);
-                       video_unregister_device(stv680->vdev);
-                       stv680->vdev = NULL;
-               }
-               if (!stv680->user) {
-                       usb_stv680_remove_disconnected (stv680);
-               } else {
-                       stv680->removed = 1;
-               }
-       }
-}
-
-static struct usb_driver stv680_driver = {
-       .name =         "stv680",
-       .probe =        stv680_probe,
-       .disconnect =   stv680_disconnect,
-       .id_table =     device_table
-};
-
-/********************************************************************
- *  Module routines
- ********************************************************************/
-
-static int __init usb_stv680_init (void)
-{
-       if (usb_register (&stv680_driver) < 0) {
-               PDEBUG (0, "STV(e): Could not setup STV0680 driver");
-               return -1;
-       }
-       PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
-
-       info(DRIVER_DESC " " DRIVER_VERSION);
-       return 0;
-}
-
-static void __exit usb_stv680_exit (void)
-{
-       usb_deregister (&stv680_driver);
-       PDEBUG (0, "STV(i): driver deregistered");
-}
-
-module_init (usb_stv680_init);
-module_exit (usb_stv680_exit);
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h
deleted file mode 100644 (file)
index ea46e00..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
- *
- *  Filename: stv680.h
- *
- *  Description:
- *     This is a USB driver for STV0680 based usb video cameras.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- * 
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- * 
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************************/
-
-/* size of usb transfers */
-#define STV680_PACKETSIZE      4096
-
-/* number of queued bulk transfers to use, may have problems if > 1 */
-#define STV680_NUMSBUF         1
-
-/* number of frames supported by the v4l part */
-#define STV680_NUMFRAMES       2
-
-/* scratch buffers for passing data to the decoders: 2 or 4 are good */
-#define STV680_NUMSCRATCH      2
-
-/* number of nul sized packets to receive before kicking the camera */
-#define STV680_MAX_NULLPACKETS 200
-
-/* number of decoding errors before kicking the camera */
-#define STV680_MAX_ERRORS      100
-
-#define USB_PENCAM_VENDOR_ID   0x0553
-#define USB_PENCAM_PRODUCT_ID  0x0202
-
-#define USB_CREATIVEGOMINI_VENDOR_ID   0x041e
-#define USB_CREATIVEGOMINI_PRODUCT_ID  0x4007
-
-#define PENCAM_TIMEOUT          1000
-/* fmt 4 */
-#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
-
-static struct usb_device_id device_table[] = {
-       {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
-       {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
-       {}
-};
-MODULE_DEVICE_TABLE (usb, device_table);
-
-struct stv680_sbuf {
-       unsigned char *data;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-enum {
-       BUFFER_UNUSED,
-       BUFFER_READY,
-       BUFFER_BUSY,
-       BUFFER_DONE,
-};
-
-/* raw camera data <- sbuf (urb transfer buf) */
-struct stv680_scratch {
-       unsigned char *data;
-       volatile int state;
-       int offset;
-       int length;
-};
-
-/* processed data for display ends up here, after bayer */
-struct stv680_frame {
-       unsigned char *data;    /* Frame buffer */
-       volatile int grabstate; /* State of grabbing */
-       unsigned char *curline;
-       int curlinepix;
-       int curpix;
-};
-
-/* this is almost the video structure uvd_t, with extra parameters for stv */
-struct usb_stv {
-       struct video_device *vdev;
-
-       struct usb_device *udev;
-
-       unsigned char bulk_in_endpointAddr;     /* __u8  the address of the bulk in endpoint */
-       char *camera_name;
-
-       unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
-       int SupportedModes;
-       int CIF;
-       int VGA;
-       int QVGA;
-       int cwidth;             /* camera width */
-       int cheight;            /* camera height */
-       int maxwidth;           /* max video width */
-       int maxheight;          /* max video height */
-       int vwidth;             /* current width for video window */
-       int vheight;            /* current height for video window */
-       unsigned long int rawbufsize;
-       unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
-
-       int origGain;
-       int origMode;           /* original camera mode */
-
-       struct mutex lock;      /* to lock the structure */
-       int user;               /* user count for exclusive use */
-       int removed;            /* device disconnected */
-       int streaming;          /* Are we streaming video? */
-       char *fbuf;             /* Videodev buffer area */
-       struct urb *urb[STV680_NUMSBUF];        /* # of queued bulk transfers */
-       int curframe;           /* Current receiving frame */
-       struct stv680_frame frame[STV680_NUMFRAMES];    /* # frames supported by v4l part */
-       int readcount;
-       int framecount;
-       int error;
-       int dropped;
-       int scratch_next;
-       int scratch_use;
-       int scratch_overflow;
-       struct stv680_scratch scratch[STV680_NUMSCRATCH];       /* for decoders */
-       struct stv680_sbuf sbuf[STV680_NUMSBUF];
-
-       unsigned int brightness;
-       unsigned int chgbright;
-       unsigned int whiteness;
-       unsigned int colour;
-       unsigned int contrast;
-       unsigned int hue;
-       unsigned int palette;
-       unsigned int depth;     /* rgb24 in bits */
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int nullpackets;
-};
-
-
-static const unsigned char red[256] = {
-       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
-       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
-       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
-       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
-       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
-       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
-       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
-       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
-       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
-       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
-       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
-       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
-       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
-       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
-       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
-       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
-       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
-       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
-       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
-       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
-       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
-       220, 220, 221, 221 
-}; 
-
-static const unsigned char green[256] = {
-       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
-       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
-       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
-       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
-       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
-       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
-       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
-       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
-       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
-       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
-       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
-       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
-       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
-       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
-       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
-       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
-       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
-       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
-       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
-       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
-       245, 245, 246, 246 
-}; 
-
-static const unsigned char blue[256] = {
-       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
-       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
-       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
-       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
-       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
-       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
-       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
-       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
-       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
-       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
-       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
-       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
-       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
-       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
-       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
-       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
-       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
-       249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
-       255, 255, 255, 255 
-}; 
diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
deleted file mode 100644 (file)
index 75ff755..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * USB NB Camera driver
- *
- * HISTORY:
- * 25-Dec-2002 Dmitri      Removed lighting, sharpness parameters, methods.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define        ULTRACAM_VENDOR_ID      0x0461
-#define        ULTRACAM_PRODUCT_ID     0x0813
-
-#define MAX_CAMERAS            4       /* How many devices we allow to connect */
-
-/*
- * This structure lives in uvd_t->user field.
- */
-typedef struct {
-       int initialized;        /* Had we already sent init sequence? */
-       int camera_model;       /* What type of IBM camera we got? */
-        int has_hdr;
-} ultracam_t;
-#define        ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams = NULL;
-
-static int debug = 0;
-
-static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth  = 8;
-static const int min_canvasHeight = 4;
-
-#define FRAMERATE_MIN  0
-#define FRAMERATE_MAX  6
-static int framerate = -1;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags,
-               "Bitfield: 0=VIDIOCSYNC, "
-               "1=B/W, "
-               "2=show hints, "
-               "3=show stats, "
-               "4=test pattern, "
-               "5=separate frames, "
-               "6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-/*
- * ultracam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ultracam_find_header() or ultracam_parse_lines() to do most
- * of work.
- *
- * 02-Nov-2000 First (mostly dummy) version.
- * 06-Nov-2000 Rewrote to dump all data into frame.
- */
-static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       int n;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-
-       /* Try to move data from queue into frame buffer */
-       n = RingQueue_GetLength(&uvd->dp);
-       if (n > 0) {
-               int m;
-               /* See how much spare we have left */
-               m = uvd->max_frame_size - frame->seqRead_Length;
-               if (n > m)
-                       n = m;
-               /* Now move that much data into frame buffer */
-               RingQueue_Dequeue(
-                       &uvd->dp,
-                       frame->data + frame->seqRead_Length,
-                       m);
-               frame->seqRead_Length += m;
-       }
-       /* See if we filled the frame */
-       if (frame->seqRead_Length >= uvd->max_frame_size) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-/*
- * ultracam_veio()
- *
- * History:
- * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ultracam_veio(
-       struct uvd *uvd,
-       unsigned char req,
-       unsigned short value,
-       unsigned short index,
-       int is_out)
-{
-       static const char proc[] = "ultracam_veio";
-       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
-       int i;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return 0;
-
-       if (!is_out) {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_rcvctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value,
-                       index,
-                       cp,
-                       sizeof(cp),
-                       1000);
-#if 1
-               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)",
-                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-                      req, value, index);
-#endif
-       } else {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_sndctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value,
-                       index,
-                       NULL,
-                       0,
-                       1000);
-       }
-       if (i < 0) {
-               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
-                   proc, i);
-               uvd->last_error = i;
-       }
-       return i;
-}
-
-/*
- * ultracam_calculate_fps()
- */
-static int ultracam_calculate_fps(struct uvd *uvd)
-{
-       return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ultracam_adjust_contrast()
- */
-static void ultracam_adjust_contrast(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ultracam_set_brightness(struct uvd *uvd)
-{
-}
-
-static void ultracam_set_hue(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ultracam_adjust_picture(struct uvd *uvd)
-{
-       ultracam_adjust_contrast(uvd);
-       ultracam_set_brightness(uvd);
-       ultracam_set_hue(uvd);
-}
-
-/*
- * ultracam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ultracam_video_stop(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- */
-static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
-{
-}
-
-static void ultracam_video_start(struct uvd *uvd)
-{
-       ultracam_reinit_iso(uvd, 0);
-}
-
-static int ultracam_resetPipe(struct uvd *uvd)
-{
-       usb_clear_halt(uvd->dev, uvd->video_endp);
-       return 0;
-}
-
-static int ultracam_alternateSetting(struct uvd *uvd, int setting)
-{
-       static const char proc[] = "ultracam_alternateSetting";
-       int i;
-       i = usb_set_interface(uvd->dev, uvd->iface, setting);
-       if (i < 0) {
-               err("%s: usb_set_interface error", proc);
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-       return 0;
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ultracam_setup_on_open(struct uvd *uvd)
-{
-       int setup_ok = 0; /* Success by default */
-       /* Send init sequence only once, it's large! */
-       if (!ULTRACAM_T(uvd)->initialized) {
-               ultracam_alternateSetting(uvd, 0x04);
-               ultracam_alternateSetting(uvd, 0x00);
-               ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
-               ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
-               ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
-               ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
-               ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
-               ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
-               ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
-               ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
-               ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
-               ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
-               ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
-               ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
-               ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
-               ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
-               ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
-               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
-               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
-               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
-               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
-               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
-               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
-               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
-               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
-               ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
-               ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
-               ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
-               ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
-               ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
-               ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
-               ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
-               ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
-               ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
-               ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
-               ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
-               ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
-               ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
-               ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
-               ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
-               ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
-               ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
-               ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
-               ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
-               ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
-               ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
-               ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
-               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
-               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
-               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
-               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
-               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
-               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
-               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
-               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
-               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
-               ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
-               ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
-               ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
-               ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
-               ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
-               ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
-               ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
-               ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
-               ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_alternateSetting(uvd, 0x04);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
-               ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
-               ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
-               ultracam_resetPipe(uvd);
-               ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
-       }
-       return setup_ok;
-}
-
-static void ultracam_configure_video(struct uvd *uvd)
-{
-       if (uvd == NULL)
-               return;
-
-       RESTRICT_TO_RANGE(init_brightness, 0, 255);
-       RESTRICT_TO_RANGE(init_contrast, 0, 255);
-       RESTRICT_TO_RANGE(init_color, 0, 255);
-       RESTRICT_TO_RANGE(init_hue, 0, 255);
-       RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       uvd->vpic.colour = init_color << 8;
-       uvd->vpic.hue = init_hue << 8;
-       uvd->vpic.brightness = init_brightness << 8;
-       uvd->vpic.contrast = init_contrast << 8;
-       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
-       uvd->vpic.depth = 24;
-       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "IBM Ultra Camera");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
-       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
-       uvd->vcap.minwidth = min_canvasWidth;
-       uvd->vcap.minheight = min_canvasHeight;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ultracam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like our camera.
- *
- * History:
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct uvd *uvd = NULL;
-       int ix, i, nas;
-       int actInterface=-1, inactInterface=-1, maxPS=0;
-       unsigned char video_ep = 0;
-
-       if (debug >= 1)
-               info("ultracam_probe(%p)", intf);
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       info("IBM Ultra camera found (rev. 0x%04x)",
-               le16_to_cpu(dev->descriptor.bcdDevice));
-
-       /* Validate found interface: must have one ISO endpoint */
-       nas = intf->num_altsetting;
-       if (debug > 0)
-               info("Number of alternate settings=%d.", nas);
-       if (nas < 8) {
-               err("Too few alternate settings for this camera!");
-               return -ENODEV;
-       }
-       /* Validate all alternate settings */
-       for (ix=0; ix < nas; ix++) {
-               const struct usb_host_interface *interface;
-               const struct usb_endpoint_descriptor *endpoint;
-
-               interface = &intf->altsetting[ix];
-               i = interface->desc.bAlternateSetting;
-               if (interface->desc.bNumEndpoints != 1) {
-                       err("Interface %d. has %u. endpoints!",
-                           interface->desc.bInterfaceNumber,
-                           (unsigned)(interface->desc.bNumEndpoints));
-                       return -ENODEV;
-               }
-               endpoint = &interface->endpoint[0].desc;
-               if (video_ep == 0)
-                       video_ep = endpoint->bEndpointAddress;
-               else if (video_ep != endpoint->bEndpointAddress) {
-                       err("Alternate settings have different endpoint addresses!");
-                       return -ENODEV;
-               }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
-                       err("Interface %d. has non-ISO endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
-                       err("Interface %d. has ISO OUT endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
-                       if (inactInterface < 0)
-                               inactInterface = i;
-                       else {
-                               err("More than one inactive alt. setting!");
-                               return -ENODEV;
-                       }
-               } else {
-                       if (actInterface < 0) {
-                               actInterface = i;
-                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-                               if (debug > 0)
-                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
-                       } else {
-                               /* Got another active alt. setting */
-                               if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
-                                       /* This one is better! */
-                                       actInterface = i;
-                                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-                                       if (debug > 0) {
-                                               info("Even better ctive setting=%d. maxPS=%d.",
-                                                    i, maxPS);
-                                       }
-                               }
-                       }
-               }
-       }
-       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
-               err("Failed to recognize the camera!");
-               return -ENODEV;
-       }
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (uvd != NULL) {
-               /* Here uvd is a fully allocated uvd object */
-               uvd->flags = flags;
-               uvd->debug = debug;
-               uvd->dev = dev;
-               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
-               uvd->ifaceAltInactive = inactInterface;
-               uvd->ifaceAltActive = actInterface;
-               uvd->video_endp = video_ep;
-               uvd->iso_packet_len = maxPS;
-               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
-               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-               uvd->canvas = VIDEOSIZE(640, 480);      /* FIXME */
-               uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
-
-               /* Initialize ibmcam-specific data */
-               assert(ULTRACAM_T(uvd) != NULL);
-               ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
-               ULTRACAM_T(uvd)->initialized = 0;
-
-               ultracam_configure_video(uvd);
-
-               i = usbvideo_RegisterVideoDevice(uvd);
-               if (i != 0) {
-                       err("usbvideo_RegisterVideoDevice() failed.");
-                       uvd = NULL;
-               }
-       }
-
-       if (uvd) {
-               usb_set_intfdata (intf, uvd);
-               return 0;
-       }
-       return -EIO;
-}
-
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
-       { }  /* Terminating entry */
-};
-
-/*
- * ultracam_init()
- *
- * This code is run to initialize the driver.
- */
-static int __init ultracam_init(void)
-{
-       struct usbvideo_cb cbTbl;
-       memset(&cbTbl, 0, sizeof(cbTbl));
-       cbTbl.probe = ultracam_probe;
-       cbTbl.setupOnOpen = ultracam_setup_on_open;
-       cbTbl.videoStart = ultracam_video_start;
-       cbTbl.videoStop = ultracam_video_stop;
-       cbTbl.processData = ultracam_ProcessIsocData;
-       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
-       cbTbl.adjustPicture = ultracam_adjust_picture;
-       cbTbl.getFPS = ultracam_calculate_fps;
-       return usbvideo_register(
-               &cams,
-               MAX_CAMERAS,
-               sizeof(ultracam_t),
-               "ultracam",
-               &cbTbl,
-               THIS_MODULE,
-               id_table);
-}
-
-static void __exit ultracam_cleanup(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-MODULE_LICENSE("GPL");
-
-module_init(ultracam_init);
-module_exit(ultracam_cleanup);
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
deleted file mode 100644 (file)
index 0b51fae..0000000
+++ /dev/null
@@ -1,2190 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-
-#include "usbvideo.h"
-
-#if defined(MAP_NR)
-#define        virt_to_page(v) MAP_NR(v)       /* Kernels 2.2.x */
-#endif
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-
-/*
- * Local prototypes.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf);
-static void usbvideo_CameraRelease(struct uvd *uvd);
-
-static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, unsigned long arg);
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
-static int usbvideo_v4l_open(struct inode *inode, struct file *file);
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
-                            size_t count, loff_t *ppos);
-static int usbvideo_v4l_close(struct inode *inode, struct file *file);
-
-static int usbvideo_StartDataPump(struct uvd *uvd);
-static void usbvideo_StopDataPump(struct uvd *uvd);
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
-                                               struct usbvideo_frame *frame);
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-static void *usbvideo_rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void usbvideo_rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-static void RingQueue_Initialize(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       init_waitqueue_head(&rq->wqh);
-}
-
-static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
-{
-       /* Make sure the requested size is a power of 2 and
-          round up if necessary. This allows index wrapping
-          using masks rather than modulo */
-
-       int i = 1;
-       assert(rq != NULL);
-       assert(rqLen > 0);
-
-       while(rqLen >> i)
-               i++;
-       if(rqLen != 1 << (i-1))
-               rqLen = 1 << i;
-
-       rq->length = rqLen;
-       rq->ri = rq->wi = 0;
-       rq->queue = usbvideo_rvmalloc(rq->length);
-       assert(rq->queue != NULL);
-}
-
-static int RingQueue_IsAllocated(const struct RingQueue *rq)
-{
-       if (rq == NULL)
-               return 0;
-       return (rq->queue != NULL) && (rq->length > 0);
-}
-
-static void RingQueue_Free(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       if (RingQueue_IsAllocated(rq)) {
-               usbvideo_rvfree(rq->queue, rq->length);
-               rq->queue = NULL;
-               rq->length = 0;
-       }
-}
-
-int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
-{
-       int rql, toread;
-
-       assert(rq != NULL);
-       assert(dst != NULL);
-
-       rql = RingQueue_GetLength(rq);
-       if(!rql)
-               return 0;
-
-       /* Clip requested length to available data */
-       if(len > rql)
-               len = rql;
-
-       toread = len;
-       if(rq->ri > rq->wi) {
-               /* Read data from tail */
-               int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
-               memcpy(dst, rq->queue + rq->ri, read);
-               toread -= read;
-               dst += read;
-               rq->ri = (rq->ri + read) & (rq->length-1);
-       }
-       if(toread) {
-               /* Read data from head */
-               memcpy(dst, rq->queue + rq->ri, toread);
-               rq->ri = (rq->ri + toread) & (rq->length-1);
-       }
-       return len;
-}
-
-EXPORT_SYMBOL(RingQueue_Dequeue);
-
-int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
-{
-       int enqueued = 0;
-
-       assert(rq != NULL);
-       assert(cdata != NULL);
-       assert(rq->length > 0);
-       while (n > 0) {
-               int m, q_avail;
-
-               /* Calculate the largest chunk that fits the tail of the ring */
-               q_avail = rq->length - rq->wi;
-               if (q_avail <= 0) {
-                       rq->wi = 0;
-                       q_avail = rq->length;
-               }
-               m = n;
-               assert(q_avail > 0);
-               if (m > q_avail)
-                       m = q_avail;
-
-               memcpy(rq->queue + rq->wi, cdata, m);
-               RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
-               cdata += m;
-               enqueued += m;
-               n -= m;
-       }
-       return enqueued;
-}
-
-EXPORT_SYMBOL(RingQueue_Enqueue);
-
-static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       interruptible_sleep_on(&rq->wqh);
-}
-
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       if (waitqueue_active(&rq->wqh))
-               wake_up_interruptible(&rq->wqh);
-}
-
-EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
-
-void RingQueue_Flush(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       rq->ri = 0;
-       rq->wi = 0;
-}
-
-EXPORT_SYMBOL(RingQueue_Flush);
-
-
-/*
- * usbvideo_VideosizeToString()
- *
- * This procedure converts given videosize value to readable string.
- *
- * History:
- * 07-Aug-2000 Created.
- * 19-Oct-2000 Reworked for usbvideo module.
- */
-static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
-{
-       char tmp[40];
-       int n;
-
-       n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));
-       assert(n < sizeof(tmp));
-       if ((buf == NULL) || (bufLen < n))
-               err("usbvideo_VideosizeToString: buffer is too small.");
-       else
-               memmove(buf, tmp, n);
-}
-
-/*
- * usbvideo_OverlayChar()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
-                                int x, int y, int ch)
-{
-       static const unsigned short digits[16] = {
-               0xF6DE, /* 0 */
-               0x2492, /* 1 */
-               0xE7CE, /* 2 */
-               0xE79E, /* 3 */
-               0xB792, /* 4 */
-               0xF39E, /* 5 */
-               0xF3DE, /* 6 */
-               0xF492, /* 7 */
-               0xF7DE, /* 8 */
-               0xF79E, /* 9 */
-               0x77DA, /* a */
-               0xD75C, /* b */
-               0xF24E, /* c */
-               0xD6DC, /* d */
-               0xF34E, /* e */
-               0xF348  /* f */
-       };
-       unsigned short digit;
-       int ix, iy;
-
-       if ((uvd == NULL) || (frame == NULL))
-               return;
-
-       if (ch >= '0' && ch <= '9')
-               ch -= '0';
-       else if (ch >= 'A' && ch <= 'F')
-               ch = 10 + (ch - 'A');
-       else if (ch >= 'a' && ch <= 'f')
-               ch = 10 + (ch - 'a');
-       else
-               return;
-       digit = digits[ch];
-
-       for (iy=0; iy < 5; iy++) {
-               for (ix=0; ix < 3; ix++) {
-                       if (digit & 0x8000) {
-                               if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {
-/* TODO */                             RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
-                               }
-                       }
-                       digit = digit << 1;
-               }
-       }
-}
-
-/*
- * usbvideo_OverlayString()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
-                                  int x, int y, const char *str)
-{
-       while (*str) {
-               usbvideo_OverlayChar(uvd, frame, x, y, *str);
-               str++;
-               x += 4; /* 3 pixels character + 1 space */
-       }
-}
-
-/*
- * usbvideo_OverlayStats()
- *
- * Overlays important debugging information.
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       const int y_diff = 8;
-       char tmp[16];
-       int x = 10, y=10;
-       long i, j, barLength;
-       const int qi_x1 = 60, qi_y1 = 10;
-       const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;
-
-       /* Call the user callback, see if we may proceed after that */
-       if (VALID_CALLBACK(uvd, overlayHook)) {
-               if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)
-                       return;
-       }
-
-       /*
-        * We draw a (mostly) hollow rectangle with qi_xxx coordinates.
-        * Left edge symbolizes the queue index 0; right edge symbolizes
-        * the full capacity of the queue.
-        */
-       barLength = qi_x2 - qi_x1 - 2;
-       if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {
-/* TODO */     long u_lo, u_hi, q_used;
-               long m_ri, m_wi, m_lo, m_hi;
-
-               /*
-                * Determine fill zones (used areas of the queue):
-                * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length
-                *
-                * if u_lo < 0 then there is no first filler.
-                */
-
-               q_used = RingQueue_GetLength(&uvd->dp);
-               if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
-                       u_hi = uvd->dp.length;
-                       u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
-               } else {
-                       u_hi = (q_used + uvd->dp.ri);
-                       u_lo = -1;
-               }
-
-               /* Convert byte indices into screen units */
-               m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);
-               m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);
-               m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;
-               m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);
-
-               for (j=qi_y1; j < (qi_y1 + qi_h); j++) {
-                       for (i=qi_x1; i < qi_x2; i++) {
-                               /* Draw border lines */
-                               if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||
-                                   (i == qi_x1) || (i == (qi_x2 - 1))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);
-                                       continue;
-                               }
-                               /* For all other points the Y coordinate does not matter */
-                               if ((i >= m_ri) && (i <= (m_ri + 3))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);
-                               } else if ((i >= m_wi) && (i <= (m_wi + 3))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);
-                               } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))
-                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);
-                       }
-               }
-       }
-
-       sprintf(tmp, "%8lx", uvd->stats.frame_num);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.urb_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.urb_length);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.data_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.header_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.colour);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.hue);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-}
-
-/*
- * usbvideo_ReportStatistics()
- *
- * This procedure prints packet and transfer statistics.
- *
- * History:
- * 14-Jan-2000 Corrected default multiplier.
- */
-static void usbvideo_ReportStatistics(const struct uvd *uvd)
-{
-       if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
-               unsigned long allPackets, badPackets, goodPackets, percent;
-               allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;
-               badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;
-               goodPackets = allPackets - badPackets;
-               /* Calculate percentage wisely, remember integer limits */
-               assert(allPackets != 0);
-               if (goodPackets < (((unsigned long)-1)/100))
-                       percent = (100 * goodPackets) / allPackets;
-               else
-                       percent = goodPackets / (allPackets / 100);
-               info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",
-                    allPackets, badPackets, percent);
-               if (uvd->iso_packet_len > 0) {
-                       unsigned long allBytes, xferBytes;
-                       char multiplier = ' ';
-                       allBytes = allPackets * uvd->iso_packet_len;
-                       xferBytes = uvd->stats.data_count;
-                       assert(allBytes != 0);
-                       if (xferBytes < (((unsigned long)-1)/100))
-                               percent = (100 * xferBytes) / allBytes;
-                       else
-                               percent = xferBytes / (allBytes / 100);
-                       /* Scale xferBytes for easy reading */
-                       if (xferBytes > 10*1024) {
-                               xferBytes /= 1024;
-                               multiplier = 'K';
-                               if (xferBytes > 10*1024) {
-                                       xferBytes /= 1024;
-                                       multiplier = 'M';
-                                       if (xferBytes > 10*1024) {
-                                               xferBytes /= 1024;
-                                               multiplier = 'G';
-                                               if (xferBytes > 10*1024) {
-                                                       xferBytes /= 1024;
-                                                       multiplier = 'T';
-                                               }
-                                       }
-                               }
-                       }
-                       info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",
-                            xferBytes, multiplier, percent);
-               }
-       }
-}
-
-/*
- * usbvideo_TestPattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe: if TRUE then entire frame is filled, otherwise the procedure
- *           continues from the current scanline.
- * pmode      0: fill the frame with solid blue color (like on VCR or TV)
- *           1: Draw a colored grid
- *
- * History:
- * 01-Feb-2000 Created.
- */
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
-{
-       struct usbvideo_frame *frame;
-       int num_cell = 0;
-       int scan_length = 0;
-       static int num_pass = 0;
-
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __FUNCTION__);
-               return;
-       }
-       if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-               err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
-               return;
-       }
-
-       /* Grab the current frame */
-       frame = &uvd->frame[uvd->curframe];
-
-       /* Optionally start at the beginning */
-       if (fullframe) {
-               frame->curline = 0;
-               frame->seqRead_Length = 0;
-       }
-#if 0
-       {       /* For debugging purposes only */
-               char tmp[20];
-               usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
-               info("testpattern: frame=%s", tmp);
-       }
-#endif
-       /* Form every scan line */
-       for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) {
-               int i;
-               unsigned char *f = frame->data +
-                       (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline);
-               for (i=0; i < VIDEOSIZE_X(frame->request); i++) {
-                       unsigned char cb=0x80;
-                       unsigned char cg = 0;
-                       unsigned char cr = 0;
-
-                       if (pmode == 1) {
-                               if (frame->curline % 32 == 0)
-                                       cb = 0, cg = cr = 0xFF;
-                               else if (i % 32 == 0) {
-                                       if (frame->curline % 32 == 1)
-                                               num_cell++;
-                                       cb = 0, cg = cr = 0xFF;
-                               } else {
-                                       cb = ((num_cell*7) + num_pass) & 0xFF;
-                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
-                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
-                               }
-                       } else {
-                               /* Just the blue screen */
-                       }
-                               
-                       *f++ = cb;
-                       *f++ = cg;
-                       *f++ = cr;
-                       scan_length += 3;
-               }
-       }
-
-       frame->frameState = FrameState_Done;
-       frame->seqRead_Length += scan_length;
-       ++num_pass;
-
-       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
-       usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_TestPattern);
-
-
-#ifdef DEBUG
-/*
- * usbvideo_HexDump()
- *
- * A debugging tool. Prints hex dumps.
- *
- * History:
- * 29-Jul-2000 Added printing of offsets.
- */
-void usbvideo_HexDump(const unsigned char *data, int len)
-{
-       const int bytes_per_line = 32;
-       char tmp[128]; /* 32*3 + 5 */
-       int i, k;
-
-       for (i=k=0; len > 0; i++, len--) {
-               if (i > 0 && ((i % bytes_per_line) == 0)) {
-                       printk("%s\n", tmp);
-                       k=0;
-               }
-               if ((i % bytes_per_line) == 0)
-                       k += sprintf(&tmp[k], "%04x: ", i);
-               k += sprintf(&tmp[k], "%02x ", data[i]);
-       }
-       if (k > 0)
-               printk("%s\n", tmp);
-}
-
-EXPORT_SYMBOL(usbvideo_HexDump);
-
-#endif
-
-/* ******************************************************************** */
-
-/* XXX: this piece of crap really wants some error handling.. */
-static void usbvideo_ClientIncModCount(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle == NULL) {
-               err("%s: uvd->handle == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle->md_module == NULL) {
-               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
-               return;
-       }
-       if (!try_module_get(uvd->handle->md_module)) {
-               err("%s: try_module_get() == 0", __FUNCTION__);
-               return;
-       }
-}
-
-static void usbvideo_ClientDecModCount(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle == NULL) {
-               err("%s: uvd->handle == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle->md_module == NULL) {
-               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
-               return;
-       }
-       module_put(uvd->handle->md_module);
-}
-
-int usbvideo_register(
-       struct usbvideo **pCams,
-       const int num_cams,
-       const int num_extra,
-       const char *driverName,
-       const struct usbvideo_cb *cbTbl,
-       struct module *md,
-       const struct usb_device_id *id_table)
-{
-       struct usbvideo *cams;
-       int i, base_size, result;
-
-       /* Check parameters for sanity */
-       if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
-               err("%s: Illegal call", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       /* Check registration callback - must be set! */
-       if (cbTbl->probe == NULL) {
-               err("%s: probe() is required!", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
-       cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
-       if (cams == NULL) {
-               err("Failed to allocate %d. bytes for usbvideo struct", base_size);
-               return -ENOMEM;
-       }
-       dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
-           __FUNCTION__, cams, base_size, num_cams);
-
-       /* Copy callbacks, apply defaults for those that are not set */
-       memmove(&cams->cb, cbTbl, sizeof(cams->cb));
-       if (cams->cb.getFrame == NULL)
-               cams->cb.getFrame = usbvideo_GetFrame;
-       if (cams->cb.disconnect == NULL)
-               cams->cb.disconnect = usbvideo_Disconnect;
-       if (cams->cb.startDataPump == NULL)
-               cams->cb.startDataPump = usbvideo_StartDataPump;
-       if (cams->cb.stopDataPump == NULL)
-               cams->cb.stopDataPump = usbvideo_StopDataPump;
-
-       cams->num_cameras = num_cams;
-       cams->cam = (struct uvd *) &cams[1];
-       cams->md_module = md;
-       if (cams->md_module == NULL)
-               warn("%s: module == NULL!", __FUNCTION__);
-       mutex_init(&cams->lock);        /* to 1 == available */
-
-       for (i = 0; i < num_cams; i++) {
-               struct uvd *up = &cams->cam[i];
-
-               up->handle = cams;
-
-               /* Allocate user_data separately because of kmalloc's limits */
-               if (num_extra > 0) {
-                       up->user_size = num_cams * num_extra;
-                       up->user_data = kmalloc(up->user_size, GFP_KERNEL);
-                       if (up->user_data == NULL) {
-                               err("%s: Failed to allocate user_data (%d. bytes)",
-                                   __FUNCTION__, up->user_size);
-                               while (i) {
-                                       up = &cams->cam[--i];
-                                       kfree(up->user_data);
-                               }
-                               kfree(cams);
-                               return -ENOMEM;
-                       }
-                       dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
-                            __FUNCTION__, i, up->user_data, up->user_size);
-               }
-       }
-
-       /*
-        * Register ourselves with USB stack.
-        */
-       strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown");
-       cams->usbdrv.name = cams->drvName;
-       cams->usbdrv.probe = cams->cb.probe;
-       cams->usbdrv.disconnect = cams->cb.disconnect;
-       cams->usbdrv.id_table = id_table;
-
-       /*
-        * Update global handle to usbvideo. This is very important
-        * because probe() can be called before usb_register() returns.
-        * If the handle is not yet updated then the probe() will fail.
-        */
-       *pCams = cams;
-       result = usb_register(&cams->usbdrv);
-       if (result) {
-               for (i = 0; i < num_cams; i++) {
-                       struct uvd *up = &cams->cam[i];
-                       kfree(up->user_data);
-               }
-               kfree(cams);
-       }
-
-       return result;
-}
-
-EXPORT_SYMBOL(usbvideo_register);
-
-/*
- * usbvideo_Deregister()
- *
- * Procedure frees all usbvideo and user data structures. Be warned that
- * if you had some dynamically allocated components in ->user field then
- * you should free them before calling here.
- */
-void usbvideo_Deregister(struct usbvideo **pCams)
-{
-       struct usbvideo *cams;
-       int i;
-
-       if (pCams == NULL) {
-               err("%s: pCams == NULL", __FUNCTION__);
-               return;
-       }
-       cams = *pCams;
-       if (cams == NULL) {
-               err("%s: cams == NULL", __FUNCTION__);
-               return;
-       }
-
-       dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
-       usb_deregister(&cams->usbdrv);
-
-       dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
-       for (i=0; i < cams->num_cameras; i++) {
-               struct uvd *up = &cams->cam[i];
-               int warning = 0;
-
-               if (up->user_data != NULL) {
-                       if (up->user_size <= 0)
-                               ++warning;
-               } else {
-                       if (up->user_size > 0)
-                               ++warning;
-               }
-               if (warning) {
-                       err("%s: Warning: user_data=$%p user_size=%d.",
-                           __FUNCTION__, up->user_data, up->user_size);
-               } else {
-                       dbg("%s: Freeing %d. $%p->user_data=$%p",
-                           __FUNCTION__, i, up, up->user_data);
-                       kfree(up->user_data);
-               }
-       }
-       /* Whole array was allocated in one chunk */
-       dbg("%s: Freed %d uvd structures",
-           __FUNCTION__, cams->num_cameras);
-       kfree(cams);
-       *pCams = NULL;
-}
-
-EXPORT_SYMBOL(usbvideo_Deregister);
-
-/*
- * usbvideo_Disconnect()
- *
- * This procedure stops all driver activity. Deallocation of
- * the interface-private structure (pointed by 'ptr') is done now
- * (if we don't have any open files) or later, when those files
- * are closed. After that driver should be removable.
- *
- * This code handles surprise removal. The uvd->user is a counter which
- * increments on open() and decrements on close(). If we see here that
- * this counter is not 0 then we have a client who still has us opened.
- * We set uvd->remove_pending flag as early as possible, and after that
- * all access to the camera will gracefully fail. These failures should
- * prompt client to (eventually) close the video device, and then - in
- * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter.
- *
- * History:
- * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone.
- * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close()
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 19-Oct-2000 Moved to usbvideo module.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf)
-{
-       struct uvd *uvd = usb_get_intfdata (intf);
-       int i;
-
-       if (uvd == NULL) {
-               err("%s($%p): Illegal call.", __FUNCTION__, intf);
-               return;
-       }
-
-       usb_set_intfdata (intf, NULL);
-
-       usbvideo_ClientIncModCount(uvd);
-       if (uvd->debug > 0)
-               info("%s(%p.)", __FUNCTION__, intf);
-
-       mutex_lock(&uvd->lock);
-       uvd->remove_pending = 1; /* Now all ISO data will be ignored */
-
-       /* At this time we ask to cancel outstanding URBs */
-       GET_CALLBACK(uvd, stopDataPump)(uvd);
-
-       for (i=0; i < USBVIDEO_NUMSBUF; i++)
-               usb_free_urb(uvd->sbuf[i].urb);
-
-       usb_put_dev(uvd->dev);
-       uvd->dev = NULL;            /* USB device is no more */
-
-       video_unregister_device(&uvd->vdev);
-       if (uvd->debug > 0)
-               info("%s: Video unregistered.", __FUNCTION__);
-
-       if (uvd->user)
-               info("%s: In use, disconnect pending.", __FUNCTION__);
-       else
-               usbvideo_CameraRelease(uvd);
-       mutex_unlock(&uvd->lock);
-       info("USB camera disconnected.");
-
-       usbvideo_ClientDecModCount(uvd);
-}
-
-/*
- * usbvideo_CameraRelease()
- *
- * This code does final release of uvd. This happens
- * after the device is disconnected -and- all clients
- * closed their files.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static void usbvideo_CameraRelease(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: Illegal call", __FUNCTION__);
-               return;
-       }
-
-       RingQueue_Free(&uvd->dp);
-       if (VALID_CALLBACK(uvd, userFree))
-               GET_CALLBACK(uvd, userFree)(uvd);
-       uvd->uvd_used = 0;      /* This is atomic, no need to take mutex */
-}
-
-/*
- * usbvideo_find_struct()
- *
- * This code searches the array of preallocated (static) structures
- * and returns index of the first one that isn't in use. Returns -1
- * if there are no free structures.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static int usbvideo_find_struct(struct usbvideo *cams)
-{
-       int u, rv = -1;
-
-       if (cams == NULL) {
-               err("No usbvideo handle?");
-               return -1;
-       }
-       mutex_lock(&cams->lock);
-       for (u = 0; u < cams->num_cameras; u++) {
-               struct uvd *uvd = &cams->cam[u];
-               if (!uvd->uvd_used) /* This one is free */
-               {
-                       uvd->uvd_used = 1;      /* In use now */
-                       mutex_init(&uvd->lock); /* to 1 == available */
-                       uvd->dev = NULL;
-                       rv = u;
-                       break;
-               }
-       }
-       mutex_unlock(&cams->lock);
-       return rv;
-}
-
-static struct file_operations usbvideo_fops = {
-       .owner =  THIS_MODULE,
-       .open =   usbvideo_v4l_open,
-       .release =usbvideo_v4l_close,
-       .read =   usbvideo_v4l_read,
-       .mmap =   usbvideo_v4l_mmap,
-       .ioctl =  usbvideo_v4l_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek = no_llseek,
-};
-static const struct video_device usbvideo_template = {
-       .owner =      THIS_MODULE,
-       .type =       VID_TYPE_CAPTURE,
-       .hardware =   VID_HARDWARE_CPIA,
-       .fops =       &usbvideo_fops,
-};
-
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
-{
-       int i, devnum;
-       struct uvd *uvd = NULL;
-
-       if (cams == NULL) {
-               err("No usbvideo handle?");
-               return NULL;
-       }
-
-       devnum = usbvideo_find_struct(cams);
-       if (devnum == -1) {
-               err("IBM USB camera driver: Too many devices!");
-               return NULL;
-       }
-       uvd = &cams->cam[devnum];
-       dbg("Device entry #%d. at $%p", devnum, uvd);
-
-       /* Not relying upon caller we increase module counter ourselves */
-       usbvideo_ClientIncModCount(uvd);
-
-       mutex_lock(&uvd->lock);
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-               if (uvd->sbuf[i].urb == NULL) {
-                       err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC);
-                       uvd->uvd_used = 0;
-                       uvd = NULL;
-                       goto allocate_done;
-               }
-       }
-       uvd->user=0;
-       uvd->remove_pending = 0;
-       uvd->last_error = 0;
-       RingQueue_Initialize(&uvd->dp);
-
-       /* Initialize video device structure */
-       uvd->vdev = usbvideo_template;
-       sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
-       /*
-        * The client is free to overwrite those because we
-        * return control to the client's probe function right now.
-        */
-allocate_done:
-       mutex_unlock(&uvd->lock);
-       usbvideo_ClientDecModCount(uvd);
-       return uvd;
-}
-
-EXPORT_SYMBOL(usbvideo_AllocateDevice);
-
-int usbvideo_RegisterVideoDevice(struct uvd *uvd)
-{
-       char tmp1[20], tmp2[20];        /* Buffers for printing */
-
-       if (uvd == NULL) {
-               err("%s: Illegal call.", __FUNCTION__);
-               return -EINVAL;
-       }
-       if (uvd->video_endp == 0) {
-               info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
-       }
-       if (uvd->paletteBits == 0) {
-               err("%s: No palettes specified!", __FUNCTION__);
-               return -EINVAL;
-       }
-       if (uvd->defaultPalette == 0) {
-               info("%s: No default palette!", __FUNCTION__);
-       }
-
-       uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
-               VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL;
-       usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize);
-       usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
-
-       if (uvd->debug > 0) {
-               info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-                    __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
-       }
-       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               err("%s: video_register_device failed", __FUNCTION__);
-               return -EPIPE;
-       }
-       if (uvd->debug > 1) {
-               info("%s: video_register_device() successful", __FUNCTION__);
-       }
-       if (uvd->dev == NULL) {
-               err("%s: uvd->dev == NULL", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       info("%s on /dev/video%d: canvas=%s videosize=%s",
-            (uvd->handle != NULL) ? uvd->handle->drvName : "???",
-            uvd->vdev.minor, tmp2, tmp1);
-
-       usb_get_dev(uvd->dev);
-       return 0;
-}
-
-EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
-
-/* ******************************************************************** */
-
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct uvd *uvd = file->private_data;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return -EFAULT;
-
-       if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
-               return -EINVAL;
-
-       pos = (unsigned long) uvd->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-/*
- * usbvideo_v4l_open()
- *
- * This is part of Video 4 Linux API. The driver can be opened by one
- * client only (checks internal counter 'uvdser'). The procedure
- * then allocates buffers needed for video processing.
- *
- * History:
- * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the
- *             camera is also initialized here (once per connect), at
- *             expense of V4L client (it waits on open() call).
- * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- */
-static int usbvideo_v4l_open(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct uvd *uvd = (struct uvd *) dev;
-       const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
-       int i, errCode = 0;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, dev);
-
-       usbvideo_ClientIncModCount(uvd);
-       mutex_lock(&uvd->lock);
-
-       if (uvd->user) {
-               err("%s: Someone tried to open an already opened device!", __FUNCTION__);
-               errCode = -EBUSY;
-       } else {
-               /* Clear statistics */
-               memset(&uvd->stats, 0, sizeof(uvd->stats));
-
-               /* Clean pointers so we know if we allocated something */
-               for (i=0; i < USBVIDEO_NUMSBUF; i++)
-                       uvd->sbuf[i].data = NULL;
-
-               /* Allocate memory for the frame buffers */
-               uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
-               uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
-               RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
-               if ((uvd->fbuf == NULL) ||
-                   (!RingQueue_IsAllocated(&uvd->dp))) {
-                       err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
-                       errCode = -ENOMEM;
-               } else {
-                       /* Allocate all buffers */
-                       for (i=0; i < USBVIDEO_NUMFRAMES; i++) {
-                               uvd->frame[i].frameState = FrameState_Unused;
-                               uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);
-                               /*
-                                * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
-                                * is not used (using read() instead).
-                                */
-                               uvd->frame[i].canvas = uvd->canvas;
-                               uvd->frame[i].seqRead_Index = 0;
-                       }
-                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-                               uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
-                               if (uvd->sbuf[i].data == NULL) {
-                                       errCode = -ENOMEM;
-                                       break;
-                               }
-                       }
-               }
-               if (errCode != 0) {
-                       /* Have to free all that memory */
-                       if (uvd->fbuf != NULL) {
-                               usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
-                               uvd->fbuf = NULL;
-                       }
-                       RingQueue_Free(&uvd->dp);
-                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-                               kfree(uvd->sbuf[i].data);
-                               uvd->sbuf[i].data = NULL;
-                       }
-               }
-       }
-
-       /* If so far no errors then we shall start the camera */
-       if (errCode == 0) {
-               /* Start data pump if we have valid endpoint */
-               if (uvd->video_endp != 0)
-                       errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
-               if (errCode == 0) {
-                       if (VALID_CALLBACK(uvd, setupOnOpen)) {
-                               if (uvd->debug > 1)
-                                       info("%s: setupOnOpen callback", __FUNCTION__);
-                               errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
-                               if (errCode < 0) {
-                                       err("%s: setupOnOpen callback failed (%d.).",
-                                           __FUNCTION__, errCode);
-                               } else if (uvd->debug > 1) {
-                                       info("%s: setupOnOpen callback successful", __FUNCTION__);
-                               }
-                       }
-                       if (errCode == 0) {
-                               uvd->settingsAdjusted = 0;
-                               if (uvd->debug > 1)
-                                       info("%s: Open succeeded.", __FUNCTION__);
-                               uvd->user++;
-                               file->private_data = uvd;
-                       }
-               }
-       }
-       mutex_unlock(&uvd->lock);
-       if (errCode != 0)
-               usbvideo_ClientDecModCount(uvd);
-       if (uvd->debug > 0)
-               info("%s: Returning %d.", __FUNCTION__, errCode);
-       return errCode;
-}
-
-/*
- * usbvideo_v4l_close()
- *
- * This is part of Video 4 Linux API. The procedure
- * stops streaming and deallocates all buffers that were earlier
- * allocated in usbvideo_v4l_open().
- *
- * History:
- * 22-Jan-2000 Moved scratch buffer deallocation here.
- * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
- * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
- */
-static int usbvideo_v4l_close(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct uvd *uvd = (struct uvd *) dev;
-       int i;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, dev);
-
-       mutex_lock(&uvd->lock);
-       GET_CALLBACK(uvd, stopDataPump)(uvd);
-       usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
-       uvd->fbuf = NULL;
-       RingQueue_Free(&uvd->dp);
-
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               kfree(uvd->sbuf[i].data);
-               uvd->sbuf[i].data = NULL;
-       }
-
-#if USBVIDEO_REPORT_STATS
-       usbvideo_ReportStatistics(uvd);
-#endif    
-
-       uvd->user--;
-       if (uvd->remove_pending) {
-               if (uvd->debug > 0)
-                       info("usbvideo_v4l_close: Final disconnect.");
-               usbvideo_CameraRelease(uvd);
-       }
-       mutex_unlock(&uvd->lock);
-       usbvideo_ClientDecModCount(uvd);
-
-       if (uvd->debug > 1)
-               info("%s: Completed.", __FUNCTION__);
-       file->private_data = NULL;
-       return 0;
-}
-
-/*
- * usbvideo_v4l_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
- * History:
- * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
- */
-static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
-{
-       struct uvd *uvd = file->private_data;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return -EIO;
-
-       switch (cmd) {
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *b = arg;
-                       *b = uvd->vcap;
-                       return 0;
-               }
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-                       *v = uvd->vchan;
-                       return 0;
-               }
-               case VIDIOCSCHAN:
-               {       
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-               case VIDIOCGPICT:
-               {
-                       struct video_picture *pic = arg;
-                       *pic = uvd->vpic;
-                       return 0;
-               }
-               case VIDIOCSPICT:
-               {
-                       struct video_picture *pic = arg;
-                       /*
-                        * Use temporary 'video_picture' structure to preserve our
-                        * own settings (such as color depth, palette) that we
-                        * aren't allowing everyone (V4L client) to change.
-                        */
-                       uvd->vpic.brightness = pic->brightness;
-                       uvd->vpic.hue = pic->hue;
-                       uvd->vpic.colour = pic->colour;
-                       uvd->vpic.contrast = pic->contrast;
-                       uvd->settingsAdjusted = 0;      /* Will force new settings */
-                       return 0;
-               }
-               case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       if(VALID_CALLBACK(uvd, setVideoMode)) {
-                               return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
-                       }
-
-                       if (vw->flags)
-                               return -EINVAL;
-                       if (vw->clipcount)
-                               return -EINVAL;
-                       if (vw->width != VIDEOSIZE_X(uvd->canvas))
-                               return -EINVAL;
-                       if (vw->height != VIDEOSIZE_Y(uvd->canvas))
-                               return -EINVAL;
-
-                       return 0;
-               }
-               case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = VIDEOSIZE_X(uvd->videosize);
-                       vw->height = VIDEOSIZE_Y(uvd->videosize);
-                       vw->chromakey = 0;
-                       if (VALID_CALLBACK(uvd, getFPS))
-                               vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
-                       else 
-                               vw->flags = 10; /* FIXME: do better! */
-                       return 0;
-               }
-               case VIDIOCGMBUF:
-               {
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset(vm, 0, sizeof(*vm));
-                       vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
-                       vm->frames = USBVIDEO_NUMFRAMES;
-                       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) 
-                         vm->offsets[i] = i * uvd->max_frame_size;
-
-                       return 0;
-               }
-               case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap *vm = arg;
-
-                       if (uvd->debug >= 1) {
-                               info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
-                                    vm->frame, vm->width, vm->height, vm->format);
-                       }
-                       /*
-                        * Check if the requested size is supported. If the requestor
-                        * requests too big a frame then we may be tricked into accessing
-                        * outside of own preallocated frame buffer (in uvd->frame).
-                        * This will cause oops or a security hole. Theoretically, we
-                        * could only clamp the size down to acceptable bounds, but then
-                        * we'd need to figure out how to insert our smaller buffer into
-                        * larger caller's buffer... this is not an easy question. So we
-                        * here just flatly reject too large requests, assuming that the
-                        * caller will resubmit with smaller size. Callers should know
-                        * what size we support (returned by VIDIOCGCAP). However vidcat,
-                        * for one, does not care and allows to ask for any size.
-                        */
-                       if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
-                           (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
-                               if (uvd->debug > 0) {
-                                       info("VIDIOCMCAPTURE: Size=%dx%d too large; "
-                                            "allowed only up to %ldx%ld", vm->width, vm->height,
-                                            VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
-                               }
-                               return -EINVAL;
-                       }
-                       /* Check if the palette is supported */
-                       if (((1L << vm->format) & uvd->paletteBits) == 0) {
-                               if (uvd->debug > 0) {
-                                       info("VIDIOCMCAPTURE: format=%d. not supported"
-                                            " (paletteBits=$%08lx)",
-                                            vm->format, uvd->paletteBits);
-                               }
-                               return -EINVAL;
-                       }
-                       if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
-                               err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
-                               return -EINVAL;
-                       }
-                       if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
-                               /* Not an error - can happen */
-                       }
-                       uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
-                       uvd->frame[vm->frame].palette = vm->format;
-
-                       /* Mark it as ready */
-                       uvd->frame[vm->frame].frameState = FrameState_Ready;
-
-                       return usbvideo_NewFrame(uvd, vm->frame);
-               }
-               case VIDIOCSYNC:
-               {
-                       int *frameNum = arg;
-                       int ret;
-
-                       if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
-                               return -EINVAL;
-                               
-                       if (uvd->debug >= 1)
-                               info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
-                       if (uvd->flags & FLAGS_NO_DECODING)
-                               ret = usbvideo_GetFrame(uvd, *frameNum);
-                       else if (VALID_CALLBACK(uvd, getFrame)) {
-                               ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
-                               if ((ret < 0) && (uvd->debug >= 1)) {
-                                       err("VIDIOCSYNC: getFrame() returned %d.", ret);
-                               }
-                       } else {
-                               err("VIDIOCSYNC: getFrame is not set");
-                               ret = -EFAULT;
-                       }
-
-                       /*
-                        * The frame is in FrameState_Done_Hold state. Release it
-                        * right now because its data is already mapped into
-                        * the user space and it's up to the application to
-                        * make use of it until it asks for another frame.
-                        */
-                       uvd->frame[*frameNum].frameState = FrameState_Unused;
-                       return ret;
-               }
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb, 0, sizeof(*vb));
-                       return 0;
-               }
-               case VIDIOCKEY:
-                       return 0;
-
-               case VIDIOCCAPTURE:
-                       return -EINVAL;
-
-               case VIDIOCSFBUF:
-
-               case VIDIOCGTUNER:
-               case VIDIOCSTUNER:
-
-               case VIDIOCGFREQ:
-               case VIDIOCSFREQ:
-
-               case VIDIOCGAUDIO:
-               case VIDIOCSAUDIO:
-                       return -EINVAL;
-
-               default:
-                       return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
-}
-
-/*
- * usbvideo_v4l_read()
- *
- * This is mostly boring stuff. We simply ask for a frame and when it
- * arrives copy all the video data from it into user space. There is
- * no obvious need to override this method.
- *
- * History:
- * 20-Oct-2000 Created.
- * 01-Nov-2000 Added mutex (uvd->lock).
- */
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
-                     size_t count, loff_t *ppos)
-{
-       struct uvd *uvd = file->private_data;
-       int noblock = file->f_flags & O_NONBLOCK;
-       int frmx = -1, i;
-       struct usbvideo_frame *frame;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
-               return -EFAULT;
-
-       if (uvd->debug >= 1)
-               info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
-
-       mutex_lock(&uvd->lock);
-
-       /* See if a frame is completed, then use it. */
-       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-               if ((uvd->frame[i].frameState == FrameState_Done) ||
-                   (uvd->frame[i].frameState == FrameState_Done_Hold) ||
-                   (uvd->frame[i].frameState == FrameState_Error)) {
-                       frmx = i;
-                       break;
-               }
-       }
-
-       /* FIXME: If we don't start a frame here then who ever does? */
-       if (noblock && (frmx == -1)) {
-               count = -EAGAIN;
-               goto read_done;
-       }
-
-       /*
-        * If no FrameState_Done, look for a FrameState_Grabbing state.
-        * See if a frame is in process (grabbing), then use it.
-        * We will need to wait until it becomes cooked, of course.
-        */
-       if (frmx == -1) {
-               for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-                       if (uvd->frame[i].frameState == FrameState_Grabbing) {
-                               frmx = i;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * If no frame is active, start one. We don't care which one
-        * it will be, so #0 is as good as any.
-        * In read access mode we don't have convenience of VIDIOCMCAPTURE
-        * to specify the requested palette (video format) on per-frame
-        * basis. This means that we have to return data in -some- format
-        * and just hope that the client knows what to do with it.
-        * The default format is configured in uvd->defaultPalette field
-        * as one of VIDEO_PALETTE_xxx values. We stuff it into the new
-        * frame and initiate the frame filling process.
-        */
-       if (frmx == -1) {
-               if (uvd->defaultPalette == 0) {
-                       err("%s: No default palette; don't know what to do!", __FUNCTION__);
-                       count = -EFAULT;
-                       goto read_done;
-               }
-               frmx = 0;
-               /*
-                * We have no per-frame control over video size.
-                * Therefore we only can use whatever size was
-                * specified as default.
-                */
-               uvd->frame[frmx].request = uvd->videosize;
-               uvd->frame[frmx].palette = uvd->defaultPalette;
-               uvd->frame[frmx].frameState = FrameState_Ready;
-               usbvideo_NewFrame(uvd, frmx);
-               /* Now frame 0 is supposed to start filling... */
-       }
-
-       /*
-        * Get a pointer to the active frame. It is either previously
-        * completed frame or frame in progress but not completed yet.
-        */
-       frame = &uvd->frame[frmx];
-
-       /*
-        * Sit back & wait until the frame gets filled and postprocessed.
-        * If we fail to get the picture [in time] then return the error.
-        * In this call we specify that we want the frame to be waited for,
-        * postprocessed and switched into FrameState_Done_Hold state. This
-        * state is used to hold the frame as "fully completed" between
-        * subsequent partial reads of the same frame.
-        */
-       if (frame->frameState != FrameState_Done_Hold) {
-               long rv = -EFAULT;
-               if (uvd->flags & FLAGS_NO_DECODING)
-                       rv = usbvideo_GetFrame(uvd, frmx);
-               else if (VALID_CALLBACK(uvd, getFrame))
-                       rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);
-               else
-                       err("getFrame is not set");
-               if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {
-                       count = rv;
-                       goto read_done;
-               }
-       }
-
-       /*
-        * Copy bytes to user space. We allow for partial reads, which
-        * means that the user application can request read less than
-        * the full frame size. It is up to the application to issue
-        * subsequent calls until entire frame is read.
-        *
-        * First things first, make sure we don't copy more than we
-        * have - even if the application wants more. That would be
-        * a big security embarassment!
-        */
-       if ((count + frame->seqRead_Index) > frame->seqRead_Length)
-               count = frame->seqRead_Length - frame->seqRead_Index;
-
-       /*
-        * Copy requested amount of data to user space. We start
-        * copying from the position where we last left it, which
-        * will be zero for a new frame (not read before).
-        */
-       if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {
-               count = -EFAULT;
-               goto read_done;
-       }
-
-       /* Update last read position */
-       frame->seqRead_Index += count;
-       if (uvd->debug >= 1) {
-               err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
-                       __FUNCTION__, count, frame->seqRead_Index);
-       }
-
-       /* Finally check if the frame is done with and "release" it */
-       if (frame->seqRead_Index >= frame->seqRead_Length) {
-               /* All data has been read */
-               frame->seqRead_Index = 0;
-
-               /* Mark it as available to be used again. */
-               uvd->frame[frmx].frameState = FrameState_Unused;
-               if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
-                       err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
-               }
-       }
-read_done:
-       mutex_unlock(&uvd->lock);
-       return count;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
-{
-       char *cdata;
-       int i, totlen = 0;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               int n = urb->iso_frame_desc[i].actual_length;
-               int st = urb->iso_frame_desc[i].status;
-
-               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-               /* Detect and ignore errored packets */
-               if (st < 0) {
-                       if (uvd->debug >= 1)
-                               err("Data error: packet=%d. len=%d. status=%d.", i, n, st);
-                       uvd->stats.iso_err_count++;
-                       continue;
-               }
-
-               /* Detect and ignore empty packets */
-               if (n <= 0) {
-                       uvd->stats.iso_skip_count++;
-                       continue;
-               }
-               totlen += n;    /* Little local accounting */
-               RingQueue_Enqueue(&uvd->dp, cdata, n);
-       }
-       return totlen;
-}
-
-static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs)
-{
-       int i, ret, len;
-       struct uvd *uvd = urb->context;
-
-       /* We don't want to do anything if we are about to be removed! */
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-#if 0
-       if (urb->actual_length > 0) {
-               info("urb=$%p status=%d. errcount=%d. length=%d.",
-                    urb, urb->status, urb->error_count, urb->actual_length);
-       } else {
-               static int c = 0;
-               if (c++ % 100 == 0)
-                       info("No Isoc data");
-       }
-#endif
-
-       if (!uvd->streaming) {
-               if (uvd->debug >= 1)
-                       info("Not streaming, but interrupt!");
-               return;
-       }
-       
-       uvd->stats.urb_count++;
-       if (urb->actual_length <= 0)
-               goto urb_done_with;
-
-       /* Copy the data received into ring queue */
-       len = usbvideo_CompressIsochronous(uvd, urb);
-       uvd->stats.urb_length = len;
-       if (len <= 0)
-               goto urb_done_with;
-
-       /* Here we got some data */
-       uvd->stats.data_count += len;
-       RingQueue_WakeUpInterruptible(&uvd->dp);
-
-urb_done_with:
-       for (i = 0; i < FRAMES_PER_DESC; i++) {
-               urb->iso_frame_desc[i].status = 0;
-               urb->iso_frame_desc[i].actual_length = 0;
-       }
-       urb->status = 0;
-       urb->dev = uvd->dev;
-       ret = usb_submit_urb (urb, GFP_KERNEL);
-       if(ret)
-               err("usb_submit_urb error (%d)", ret);
-       return;
-}
-
-/*
- * usbvideo_StartDataPump()
- *
- * History:
- * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead
- *             of hardcoded values. Simplified by using for loop,
- *             allowed any number of URBs.
- */
-static int usbvideo_StartDataPump(struct uvd *uvd)
-{
-       struct usb_device *dev = uvd->dev;
-       int i, errFlag;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, uvd);
-
-       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-               err("%s: Camera is not operational", __FUNCTION__);
-               return -EFAULT;
-       }
-       uvd->curframe = -1;
-
-       /* Alternate interface 1 is is the biggest frame size */
-       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
-       if (i < 0) {
-               err("%s: usb_set_interface error", __FUNCTION__);
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-       if (VALID_CALLBACK(uvd, videoStart))
-               GET_CALLBACK(uvd, videoStart)(uvd);
-       else 
-               err("%s: videoStart not set", __FUNCTION__);
-
-       /* We double buffer the Iso lists */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               int j, k;
-               struct urb *urb = uvd->sbuf[i].urb;
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = uvd->sbuf[i].data;
-               urb->complete = usbvideo_IsocIrq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
-               for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = uvd->iso_packet_len;
-               }
-       }
-
-       /* Submit all URBs */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-               if (errFlag)
-                       err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
-       }
-
-       uvd->streaming = 1;
-       if (uvd->debug > 1)
-               info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
-       return 0;
-}
-
-/*
- * usbvideo_StopDataPump()
- *
- * This procedure stops streaming and deallocates URBs. Then it
- * activates zero-bandwidth alt. setting of the video interface.
- *
- * History:
- * 22-Jan-2000 Corrected order of actions to work after surprise removal.
- * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
- */
-static void usbvideo_StopDataPump(struct uvd *uvd)
-{
-       int i, j;
-
-       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-               return;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, uvd);
-
-       /* Unschedule all of the iso td's */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               usb_kill_urb(uvd->sbuf[i].urb);
-       }
-       if (uvd->debug > 1)
-               info("%s: streaming=0", __FUNCTION__);
-       uvd->streaming = 0;
-
-       if (!uvd->remove_pending) {
-               /* Invoke minidriver's magic to stop the camera */
-               if (VALID_CALLBACK(uvd, videoStop))
-                       GET_CALLBACK(uvd, videoStop)(uvd);
-               else 
-                       err("%s: videoStop not set", __FUNCTION__);
-
-               /* Set packet size to 0 */
-               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
-               if (j < 0) {
-                       err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
-                       uvd->last_error = j;
-               }
-       }
-}
-
-/*
- * usbvideo_NewFrame()
- *
- * History:
- * 29-Mar-00 Added copying of previous frame into the current one.
- * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
- */
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
-{
-       struct usbvideo_frame *frame;
-       int n;
-
-       if (uvd->debug > 1)
-               info("usbvideo_NewFrame($%p,%d.)", uvd, framenum);
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /*  ready to be grabbed into, then use it instead */
-       if (uvd->curframe != -1)
-               return 0;
-
-       /* If necessary we adjust picture settings between frames */
-       if (!uvd->settingsAdjusted) {
-               if (VALID_CALLBACK(uvd, adjustPicture))
-                       GET_CALLBACK(uvd, adjustPicture)(uvd);
-               uvd->settingsAdjusted = 1;
-       }
-
-       n = (framenum + 1) % USBVIDEO_NUMFRAMES;
-       if (uvd->frame[n].frameState == FrameState_Ready)
-               framenum = n;
-
-       frame = &uvd->frame[framenum];
-
-       frame->frameState = FrameState_Grabbing;
-       frame->scanstate = ScanState_Scanning;
-       frame->seqRead_Length = 0;      /* Accumulated in xxx_parse_data() */
-       frame->deinterlace = Deinterlace_None;
-       frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */
-       uvd->curframe = framenum;
-
-       /*
-        * Normally we would want to copy previous frame into the current one
-        * before we even start filling it with data; this allows us to stop
-        * filling at any moment; top portion of the frame will be new and
-        * bottom portion will stay as it was in previous frame. If we don't
-        * do that then missing chunks of video stream will result in flickering
-        * portions of old data whatever it was before.
-        *
-        * If we choose not to copy previous frame (to, for example, save few
-        * bus cycles - the frame can be pretty large!) then we have an option
-        * to clear the frame before using. If we experience losses in this
-        * mode then missing picture will be black (no flickering).
-        *
-        * Finally, if user chooses not to clean the current frame before
-        * filling it with data then the old data will be visible if we fail
-        * to refill entire frame with new data.
-        */
-       if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
-               /* This copies previous frame into this one to mask losses */
-               int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
-               memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
-       } else {
-               if (uvd->flags & FLAGS_CLEAN_FRAMES) {
-                       /* This provides a "clean" frame but slows things down */
-                       memset(frame->data, 0, uvd->max_frame_size);
-               }
-       }
-       return 0;
-}
-
-/*
- * usbvideo_CollectRawData()
- *
- * This procedure can be used instead of 'processData' callback if you
- * only want to dump the raw data from the camera into the output
- * device (frame buffer). You can look at it with V4L client, but the
- * image will be unwatchable. The main purpose of this code and of the
- * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from
- * new, unknown cameras. This procedure will be automatically invoked
- * instead of the specified callback handler when uvd->flags has bit
- * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
- * based on usbvideo can use this feature at any time.
- */
-static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       int n;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-
-       /* Try to move data from queue into frame buffer */
-       n = RingQueue_GetLength(&uvd->dp);
-       if (n > 0) {
-               int m;
-               /* See how much space we have left */
-               m = uvd->max_frame_size - frame->seqRead_Length;
-               if (n > m)
-                       n = m;
-               /* Now move that much data into frame buffer */
-               RingQueue_Dequeue(
-                       &uvd->dp,
-                       frame->data + frame->seqRead_Length,
-                       m);
-               frame->seqRead_Length += m;
-       }
-       /* See if we filled the frame */
-       if (frame->seqRead_Length >= uvd->max_frame_size) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
-{
-       struct usbvideo_frame *frame = &uvd->frame[frameNum];
-
-       if (uvd->debug >= 2)
-               info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
-
-       switch (frame->frameState) {
-        case FrameState_Unused:
-               if (uvd->debug >= 2)
-                       info("%s: FrameState_Unused", __FUNCTION__);
-               return -EINVAL;
-        case FrameState_Ready:
-        case FrameState_Grabbing:
-        case FrameState_Error:
-        {
-               int ntries, signalPending;
-       redo:
-               if (!CAMERA_IS_OPERATIONAL(uvd)) {
-                       if (uvd->debug >= 2)
-                               info("%s: Camera is not operational (1)", __FUNCTION__);
-                       return -EIO;
-               }
-               ntries = 0; 
-               do {
-                       RingQueue_InterruptibleSleepOn(&uvd->dp);
-                       signalPending = signal_pending(current);
-                       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-                               if (uvd->debug >= 2)
-                                       info("%s: Camera is not operational (2)", __FUNCTION__);
-                               return -EIO;
-                       }
-                       assert(uvd->fbuf != NULL);
-                       if (signalPending) {
-                               if (uvd->debug >= 2)
-                                       info("%s: Signal=$%08x", __FUNCTION__, signalPending);
-                               if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
-                                       usbvideo_TestPattern(uvd, 1, 0);
-                                       uvd->curframe = -1;
-                                       uvd->stats.frame_num++;
-                                       if (uvd->debug >= 2)
-                                               info("%s: Forced test pattern screen", __FUNCTION__);
-                                       return 0;
-                               } else {
-                                       /* Standard answer: Interrupted! */
-                                       if (uvd->debug >= 2)
-                                               info("%s: Interrupted!", __FUNCTION__);
-                                       return -EINTR;
-                               }
-                       } else {
-                               /* No signals - we just got new data in dp queue */
-                               if (uvd->flags & FLAGS_NO_DECODING)
-                                       usbvideo_CollectRawData(uvd, frame);
-                               else if (VALID_CALLBACK(uvd, processData))
-                                       GET_CALLBACK(uvd, processData)(uvd, frame);
-                               else 
-                                       err("%s: processData not set", __FUNCTION__);
-                       }
-               } while (frame->frameState == FrameState_Grabbing);
-               if (uvd->debug >= 2) {
-                       info("%s: Grabbing done; state=%d. (%lu. bytes)",
-                            __FUNCTION__, frame->frameState, frame->seqRead_Length);
-               }
-               if (frame->frameState == FrameState_Error) {
-                       int ret = usbvideo_NewFrame(uvd, frameNum);
-                       if (ret < 0) {
-                               err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
-                               return ret;
-                       }
-                       goto redo;
-               }
-               /* Note that we fall through to meet our destiny below */
-        }
-        case FrameState_Done:
-               /*
-                * Do all necessary postprocessing of data prepared in
-                * "interrupt" code and the collecting code above. The
-                * frame gets marked as FrameState_Done by queue parsing code.
-                * This status means that we collected enough data and
-                * most likely processed it as we went through. However
-                * the data may need postprocessing, such as deinterlacing
-                * or picture adjustments implemented in software (horror!)
-                *
-                * As soon as the frame becomes "final" it gets promoted to
-                * FrameState_Done_Hold status where it will remain until the
-                * caller consumed all the video data from the frame. Then
-                * the empty shell of ex-frame is thrown out for dogs to eat.
-                * But we, worried about pets, will recycle the frame!
-                */
-               uvd->stats.frame_num++;
-               if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
-                       if (VALID_CALLBACK(uvd, postProcess))
-                               GET_CALLBACK(uvd, postProcess)(uvd, frame);
-                       if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
-                               usbvideo_SoftwareContrastAdjustment(uvd, frame);
-               }
-               frame->frameState = FrameState_Done_Hold;
-               if (uvd->debug >= 2)
-                       info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
-               return 0;
-
-       case FrameState_Done_Hold:
-               /*
-                * We stay in this state indefinitely until someone external,
-                * like ioctl() or read() call finishes digesting the frame
-                * data. Then it will mark the frame as FrameState_Unused and
-                * it will be released back into the wild to roam freely.
-                */
-               if (uvd->debug >= 2)
-                       info("%s: FrameState_Done_Hold state.", __FUNCTION__);
-               return 0;
-       }
-
-       /* Catch-all for other cases. We shall not be here. */
-       err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
-       frame->frameState = FrameState_Unused;
-       return 0;
-}
-
-/*
- * usbvideo_DeinterlaceFrame()
- *
- * This procedure deinterlaces the given frame. Some cameras produce
- * only half of scanlines - sometimes only even lines, sometimes only
- * odd lines. The deinterlacing method is stored in frame->deinterlace
- * variable.
- *
- * Here we scan the frame vertically and replace missing scanlines with
- * average between surrounding ones - before and after. If we have no
- * line above then we just copy next line. Similarly, if we need to
- * create a last line then preceding line is used.
- */
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       if ((uvd == NULL) || (frame == NULL))
-               return;
-
-       if ((frame->deinterlace == Deinterlace_FillEvenLines) ||
-           (frame->deinterlace == Deinterlace_FillOddLines))
-       {
-               const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-               int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1;
-
-               for (; i < VIDEOSIZE_Y(frame->request); i += 2) {
-                       const unsigned char *fs1, *fs2;
-                       unsigned char *fd;
-                       int ip, in, j;  /* Previous and next lines */
-
-                       /*
-                        * Need to average lines before and after 'i'.
-                        * If we go out of bounds seeking those lines then
-                        * we point back to existing line.
-                        */
-                       ip = i - 1;     /* First, get rough numbers */
-                       in = i + 1;
-
-                       /* Now validate */
-                       if (ip < 0)
-                               ip = in;
-                       if (in >= VIDEOSIZE_Y(frame->request))
-                               in = ip;
-
-                       /* Sanity check */
-                       if ((ip < 0) || (in < 0) ||
-                           (ip >= VIDEOSIZE_Y(frame->request)) ||
-                           (in >= VIDEOSIZE_Y(frame->request)))
-                       {
-                               err("Error: ip=%d. in=%d. req.height=%ld.",
-                                   ip, in, VIDEOSIZE_Y(frame->request));
-                               break;
-                       }
-
-                       /* Now we need to average lines 'ip' and 'in' to produce line 'i' */
-                       fs1 = frame->data + (v4l_linesize * ip);
-                       fs2 = frame->data + (v4l_linesize * in);
-                       fd = frame->data + (v4l_linesize * i);
-
-                       /* Average lines around destination */
-                       for (j=0; j < v4l_linesize; j++) {
-                               fd[j] = (unsigned char)((((unsigned) fs1[j]) +
-                                                        ((unsigned)fs2[j])) >> 1);
-                       }
-               }
-       }
-
-       /* Optionally display statistics on the screen */
-       if (uvd->flags & FLAGS_OVERLAY_STATS)
-               usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
-
-/*
- * usbvideo_SoftwareContrastAdjustment()
- *
- * This code adjusts the contrast of the frame, assuming RGB24 format.
- * As most software image processing, this job is CPU-intensive.
- * Get a camera that supports hardware adjustment!
- *
- * History:
- * 09-Feb-2001  Created.
- */
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, 
-                                               struct usbvideo_frame *frame)
-{
-       int i, j, v4l_linesize;
-       signed long adj;
-       const int ccm = 128; /* Color correction median - see below */
-
-       if ((uvd == NULL) || (frame == NULL)) {
-               err("%s: Illegal call.", __FUNCTION__);
-               return;
-       }
-       adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(adj, -ccm, ccm+1);
-       if (adj == 0) {
-               /* In rare case of no adjustment */
-               return;
-       }
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-       for (i=0; i < VIDEOSIZE_Y(frame->request); i++) {
-               unsigned char *fd = frame->data + (v4l_linesize * i);
-               for (j=0; j < v4l_linesize; j++) {
-                       signed long v = (signed long) fd[j];
-                       /* Magnify up to 2 times, reduce down to zero */
-                       v = 128 + ((ccm + adj) * (v - 128)) / ccm;
-                       RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */
-                       fd[j] = (unsigned char) v;
-               }
-       }
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
deleted file mode 100644 (file)
index 135433c..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef usbvideo_h
-#define        usbvideo_h
-
-#include <linux/config.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-/* Most helpful debugging aid */
-#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
-
-#define USBVIDEO_REPORT_STATS  1       /* Set to 0 to block statistics on close */
-
-/* Bit flags (options) */
-#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
-#define        FLAGS_MONOCHROME                (1 << 1)
-#define FLAGS_DISPLAY_HINTS            (1 << 2)
-#define FLAGS_OVERLAY_STATS            (1 << 3)
-#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
-#define FLAGS_SEPARATE_FRAMES          (1 << 5)
-#define FLAGS_CLEAN_FRAMES             (1 << 6)
-#define        FLAGS_NO_DECODING               (1 << 7)
-
-/* Bit flags for frames (apply to the frame where they are specified) */
-#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST  (1 << 0)
-
-/* Camera capabilities (maximum) */
-#define CAMERA_URB_FRAMES       32
-#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
-#define FRAMES_PER_DESC                (CAMERA_URB_FRAMES)
-#define FRAME_SIZE_PER_DESC    (CAMERA_MAX_ISO_PACKET)
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
-
-#define V4L_BYTES_PER_PIXEL     3      /* Because we produce RGB24 */
-
-/*
- * Use this macro to construct constants for different video sizes.
- * We have to deal with different video sizes that have to be
- * configured in the device or compared against when we receive
- * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y
- * #defines and that's the end of story. However this solution
- * does not allow to convert between real pixel sizes and the
- * constant (integer) value that may be used to tag a frame or
- * whatever. The set of macros below constructs videosize constants
- * from the pixel size and allows to reconstruct the pixel size
- * from the combined value later.
- */
-#define        VIDEOSIZE(x,y)  (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16))
-#define        VIDEOSIZE_X(vs) ((vs) & 0xFFFFL)
-#define        VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL)
-typedef unsigned long videosize_t;
-
-/*
- * This macro checks if the camera is still operational. The 'uvd'
- * pointer must be valid, uvd->dev must be valid, we are not
- * removing the device and the device has not erred on us.
- */
-#define CAMERA_IS_OPERATIONAL(uvd) (\
-       (uvd != NULL) && \
-       ((uvd)->dev != NULL) && \
-       ((uvd)->last_error == 0) && \
-       (!(uvd)->remove_pending))
-
-/*
- * We use macros to do YUV -> RGB conversion because this is
- * very important for speed and totally unimportant for size.
- *
- * YUV -> RGB Conversion
- * ---------------------
- *
- * B = 1.164*(Y-16)                + 2.018*(V-128)
- * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
- * R = 1.164*(Y-16) + 1.596*(U-128)
- *
- * If you fancy integer arithmetics (as you should), hear this:
- *
- * 65536*B = 76284*(Y-16)                + 132252*(V-128)
- * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
- * 65536*R = 76284*(Y-16) + 104595*(U-128)
- *
- * Make sure the output values are within [0..255] range.
- */
-#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
-#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
-    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
-    mm_y = (my) - 16;  \
-    mm_u = (mu) - 128; \
-    mm_v = (mv) - 128; \
-    mm_yc= mm_y * 76284; \
-    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
-    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
-    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
-    mb = LIMIT_RGB(mm_b); \
-    mg = LIMIT_RGB(mm_g); \
-    mr = LIMIT_RGB(mm_r); \
-}
-
-#define        RING_QUEUE_SIZE         (128*1024)      /* Must be a power of 2 */
-#define        RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
-#define        RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
-#define        RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
-
-struct RingQueue {
-       unsigned char *queue;   /* Data from the Isoc data pump */
-       int length;             /* How many bytes allocated for the queue */
-       int wi;                 /* That's where we write */
-       int ri;                 /* Read from here until you hit write index */
-       wait_queue_head_t wqh;  /* Processes waiting */
-};
-
-enum ScanState {
-       ScanState_Scanning,     /* Scanning for header */
-       ScanState_Lines         /* Parsing lines */
-};
-
-/* Completion states of the data parser */
-enum ParseState {
-       scan_Continue,          /* Just parse next item */
-       scan_NextFrame,         /* Frame done, send it to V4L */
-       scan_Out,               /* Not enough data for frame */
-       scan_EndParse           /* End parsing */
-};
-
-enum FrameState {
-       FrameState_Unused,      /* Unused (no MCAPTURE) */
-       FrameState_Ready,       /* Ready to start grabbing */
-       FrameState_Grabbing,    /* In the process of being grabbed into */
-       FrameState_Done,        /* Finished grabbing, but not been synced yet */
-       FrameState_Done_Hold,   /* Are syncing or reading */
-       FrameState_Error,       /* Something bad happened while processing */
-};
-
-/*
- * Some frames may contain only even or odd lines. This type
- * specifies what type of deinterlacing is required.
- */
-enum Deinterlace {
-       Deinterlace_None=0,
-       Deinterlace_FillOddLines,
-       Deinterlace_FillEvenLines
-};
-
-#define USBVIDEO_NUMFRAMES     2       /* How many frames we work with */
-#define USBVIDEO_NUMSBUF       2       /* How many URBs linked in a ring */
-
-/* This structure represents one Isoc request - URB and buffer */
-struct usbvideo_sbuf {
-       char *data;
-       struct urb *urb;
-};
-
-struct usbvideo_frame {
-       char *data;             /* Frame buffer */
-       unsigned long header;   /* Significant bits from the header */
-
-       videosize_t canvas;     /* The canvas (max. image) allocated */
-       videosize_t request;    /* That's what the application asked for */
-       unsigned short palette; /* The desired format */
-
-       enum FrameState frameState;/* State of grabbing */
-       enum ScanState scanstate;       /* State of scanning */
-       enum Deinterlace deinterlace;
-       int flags;              /* USBVIDEO_FRAME_FLAG_xxx bit flags */
-
-       int curline;            /* Line of frame we're working on */
-
-       long seqRead_Length;    /* Raw data length of frame */
-       long seqRead_Index;     /* Amount of data that has been already read */
-
-       void *user;             /* Additional data that user may need */
-};
-
-/* Statistics that can be overlaid on screen */
-struct usbvideo_statistics {
-        unsigned long frame_num;       /* Sequential number of the frame */
-        unsigned long urb_count;        /* How many URBs we received so far */
-        unsigned long urb_length;       /* Length of last URB */
-        unsigned long data_count;       /* How many bytes we received */
-        unsigned long header_count;     /* How many frame headers we found */
-       unsigned long iso_skip_count;   /* How many empty ISO packets received */
-       unsigned long iso_err_count;    /* How many bad ISO packets received */
-};
-
-struct usbvideo;
-
-struct uvd {
-       struct video_device vdev;       /* Must be the first field! */
-       struct usb_device *dev;
-       struct usbvideo *handle;        /* Points back to the struct usbvideo */
-       void *user_data;                /* Camera-dependent data */
-       int user_size;                  /* Size of that camera-dependent data */
-       int debug;                      /* Debug level for usbvideo */
-       unsigned char iface;            /* Video interface number */
-       unsigned char video_endp;
-       unsigned char ifaceAltActive;
-       unsigned char ifaceAltInactive; /* Alt settings */
-       unsigned long flags;            /* FLAGS_USBVIDEO_xxx */
-       unsigned long paletteBits;      /* Which palettes we accept? */
-       unsigned short defaultPalette;  /* What palette to use for read() */
-       struct mutex lock;
-       int user;               /* user count for exclusive use */
-
-       videosize_t videosize;  /* Current setting */
-       videosize_t canvas;     /* This is the width,height of the V4L canvas */
-       int max_frame_size;     /* Bytes in one video frame */
-
-       int uvd_used;           /* Is this structure in use? */
-       int streaming;          /* Are we streaming Isochronous? */
-       int grabbing;           /* Are we grabbing? */
-       int settingsAdjusted;   /* Have we adjusted contrast etc.? */
-       int last_error;         /* What calamity struck us? */
-
-       char *fbuf;             /* Videodev buffer area */
-       int fbuf_size;          /* Videodev buffer size */
-
-       int curframe;
-       int iso_packet_len;     /* Videomode-dependent, saves bus bandwidth */
-
-       struct RingQueue dp;    /* Isoc data pump */
-       struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
-       struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
-
-       volatile int remove_pending;    /* If set then about to exit */
-
-       struct video_picture vpic, vpic_old;    /* Picture settings */
-       struct video_capability vcap;           /* Video capabilities */
-       struct video_channel vchan;     /* May be used for tuner support */
-       struct usbvideo_statistics stats;
-       char videoName[32];             /* Holds name like "video7" */
-};
-
-/*
- * usbvideo callbacks (virtual methods). They are set when usbvideo
- * services are registered. All of these default to NULL, except those
- * that default to usbvideo-provided methods.
- */
-struct usbvideo_cb {
-       int (*probe)(struct usb_interface *, const struct usb_device_id *);
-       void (*userFree)(struct uvd *);
-       void (*disconnect)(struct usb_interface *);
-       int (*setupOnOpen)(struct uvd *);
-       void (*videoStart)(struct uvd *);
-       void (*videoStop)(struct uvd *);
-       void (*processData)(struct uvd *, struct usbvideo_frame *);
-       void (*postProcess)(struct uvd *, struct usbvideo_frame *);
-       void (*adjustPicture)(struct uvd *);
-       int (*getFPS)(struct uvd *);
-       int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
-       int (*getFrame)(struct uvd *, int);
-       int (*startDataPump)(struct uvd *uvd);
-       void (*stopDataPump)(struct uvd *uvd);
-       int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
-};
-
-struct usbvideo {
-       int num_cameras;                /* As allocated */
-       struct usb_driver usbdrv;       /* Interface to the USB stack */
-       char drvName[80];               /* Driver name */
-       struct mutex lock;              /* Mutex protecting camera structures */
-       struct usbvideo_cb cb;          /* Table of callbacks (virtual methods) */
-       struct video_device vdt;        /* Video device template */
-       struct uvd *cam;                        /* Array of camera structures */
-       struct module *md_module;       /* Minidriver module */
-};
-
-
-/*
- * This macro retrieves callback address from the struct uvd object.
- * No validity checks are done here, so be sure to check the
- * callback beforehand with VALID_CALLBACK.
- */
-#define        GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName)
-
-/*
- * This macro returns either callback pointer or NULL. This is safe
- * macro, meaning that most of components of data structures involved
- * may be NULL - this only results in NULL being returned. You may
- * wish to use this macro to make sure that the callback is callable.
- * However keep in mind that those checks take time.
- */
-#define        VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
-               ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
-
-int  RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
-int  RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
-void RingQueue_Flush(struct RingQueue *rq);
-
-static inline int RingQueue_GetLength(const struct RingQueue *rq)
-{
-       return (rq->wi - rq->ri + rq->length) & (rq->length-1);
-}
-
-static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
-{
-       return rq->length - RingQueue_GetLength(rq);
-}
-
-void usbvideo_DrawLine(
-       struct usbvideo_frame *frame,
-       int x1, int y1,
-       int x2, int y2,
-       unsigned char cr, unsigned char cg, unsigned char cb);
-void usbvideo_HexDump(const unsigned char *data, int len);
-void usbvideo_SayAndWait(const char *what);
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
-
-/* Memory allocation routines */
-unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
-
-int usbvideo_register(
-       struct usbvideo **pCams,
-       const int num_cams,
-       const int num_extra,
-       const char *driverName,
-       const struct usbvideo_cb *cbTable,
-       struct module *md,
-       const struct usb_device_id *id_table);
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
-int usbvideo_RegisterVideoDevice(struct uvd *uvd);
-void usbvideo_Deregister(struct usbvideo **uvt);
-
-int usbvideo_v4l_initialize(struct video_device *dev);
-
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
-
-/*
- * This code performs bounds checking - use it when working with
- * new formats, or else you may get oopses all over the place.
- * If pixel falls out of bounds then it gets shoved back (as close
- * to place of offence as possible) and is painted bright red.
- *
- * There are two important concepts: frame width, height and
- * V4L canvas width, height. The former is the area requested by
- * the application -for this very frame-. The latter is the largest
- * possible frame that we can serve (we advertise that via V4L ioctl).
- * The frame data is expected to be formatted as lines of length
- * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
- */
-static inline void RGB24_PUTPIXEL(
-       struct usbvideo_frame *fr,
-       int ix, int iy,
-       unsigned char vr,
-       unsigned char vg,
-       unsigned char vb)
-{
-       register unsigned char *pf;
-       int limiter = 0, mx, my;
-       mx = ix;
-       my = iy;
-       if (mx < 0) {
-               mx=0;
-               limiter++;
-       } else if (mx >= VIDEOSIZE_X((fr)->request)) {
-               mx= VIDEOSIZE_X((fr)->request) - 1;
-               limiter++;
-       }
-       if (my < 0) {
-               my = 0;
-               limiter++;
-       } else if (my >= VIDEOSIZE_Y((fr)->request)) {
-               my = VIDEOSIZE_Y((fr)->request) - 1;
-               limiter++;
-       }
-       pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix));
-       if (limiter) {
-               *pf++ = 0;
-               *pf++ = 0;
-               *pf++ = 0xFF;
-       } else {
-               *pf++ = (vb);
-               *pf++ = (vg);
-               *pf++ = (vr);
-       }
-}
-
-#endif /* usbvideo_h */
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
deleted file mode 100644 (file)
index 1d06e53..0000000
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*
- * USB ViCam WebCam driver
- * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
- *                    Christopher L Cheney (ccheney@cheney.cx),
- *                    Pavel Machek (pavel@suse.cz),
- *                    John Tyner (jtyner@cs.ucr.edu),
- *                    Monroe Williams (monroe@pobox.com)
- *
- * Supports 3COM HomeConnect PC Digital WebCam
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This source code is based heavily on the CPiA webcam driver which was
- * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
- *
- * Portions of this code were also copied from usbvideo.c
- *
- * Special thanks to the the whole team at Sourceforge for help making
- * this driver become a reality.  Notably:
- * Andy Armstrong who reverse engineered the color encoding and
- * Pavel Machek and Chris Cheney who worked on reverse engineering the
- *    camera controls and wrote the first generation driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-#include "usbvideo.h"
-
-// #define VICAM_DEBUG
-
-#ifdef VICAM_DEBUG
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
-#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
-#else
-#define DBG(fmn,args...) do {} while(0)
-#endif
-
-#define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
-#define DRIVER_DESC             "ViCam WebCam Driver"
-
-/* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID    0x04c1
-#define USB_VICAM_PRODUCT_ID   0x009d
-
-#define VICAM_BYTES_PER_PIXEL   3
-#define VICAM_MAX_READ_SIZE     (512*242+128)
-#define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
-#define VICAM_FRAMES            2
-
-#define VICAM_HEADER_SIZE       64
-
-#define clamp( x, l, h )        max_t( __typeof__( x ),         \
-                                       ( l ),                   \
-                                       min_t( __typeof__( x ),  \
-                                              ( h ),            \
-                                              ( x ) ) )
-
-/* Not sure what all the bytes in these char
- * arrays do, but they're necessary to make
- * the camera work.
- */
-
-static unsigned char setup1[] = {
-       0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
-       0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
-       0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
-       0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
-       0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
-};
-
-static unsigned char setup2[] = {
-       0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
-       0x00, 0x00
-};
-
-static unsigned char setup3[] = {
-       0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
-};
-
-static unsigned char setup4[] = {
-       0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
-       0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
-       0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
-       0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
-       0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
-       0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
-       0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
-       0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
-       0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
-       0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
-       0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
-       0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
-       0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
-       0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
-       0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
-       0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
-       0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
-       0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
-       0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
-       0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
-       0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
-       0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
-       0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
-       0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
-       0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
-       0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
-       0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
-       0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
-       0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
-       0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
-       0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
-       0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
-       0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
-       0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
-       0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
-       0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
-       0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
-       0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
-       0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
-       0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
-       0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
-       0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
-       0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
-       0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
-       0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
-       0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
-       0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
-       0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
-       0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
-       0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
-       0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
-       0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
-       0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
-       0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
-       0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
-       0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
-       0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
-       0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-       0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
-       0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
-       0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
-       0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
-       0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
-       0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
-       0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
-       0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
-       0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
-       0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
-       0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
-       0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
-       0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
-       0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
-       0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
-       0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
-       0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
-       0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
-       0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
-       0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
-       0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
-       0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
-       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
-       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
-       0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
-       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
-       0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
-       0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
-       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
-       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
-       0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
-       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
-       0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
-       0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
-       0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
-       0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-       0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
-       0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-       0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
-       0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
-       0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
-       0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
-       0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
-       0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
-       0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
-       0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
-       0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
-       0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
-       0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
-       0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
-       0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
-       0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
-       0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
-       0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
-       0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
-       0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
-       0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
-       0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
-       0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
-       0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
-       0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
-       0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
-       0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
-       0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
-       0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
-       0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
-       0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
-       0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-       0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
-       0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
-       0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
-       0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
-       0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
-       0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
-       0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
-       0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
-       0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
-       0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-       0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
-       0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
-       0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
-       0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
-       0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
-       0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
-       0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
-       0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
-       0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-       0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
-       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
-       0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
-       0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
-       0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-       0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
-       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
-       0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-       0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
-       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
-       0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-       0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
-       0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
-       0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
-       0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
-       0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
-       0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
-       0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
-       0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
-       0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
-       0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
-       0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
-       0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-       0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-       0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
-       0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-       0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
-       0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
-       0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
-       0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
-       0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
-       0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
-       0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
-       0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-       0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
-       0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
-       0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
-       0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
-       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
-       0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
-       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
-       0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
-       0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-       0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static unsigned char setup5[] = {
-       0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
-       0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
-       0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
-       0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
-       0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
-       0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
-       0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
-       0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
-       0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
-       0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
-       0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
-       0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
-       0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
-       0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
-       0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
-       0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
-       0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
-       0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
-       0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
-       0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
-       0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
-       0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
-       0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
-       0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
-       0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
-       0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
-       0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
-       0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
-       0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
-       0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
-       0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
-       0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
-       0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
-       0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
-       0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
-       0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
-       0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
-       0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
-       0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
-};
-
-/* rvmalloc / rvfree copied from usbvideo.c
- *
- * Not sure why these are not yet non-statics which I can reference through
- * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
- * in the future.
- * 
-*/
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-struct vicam_camera {
-       u16 shutter_speed;      // capture shutter speed
-       u16 gain;               // capture gain
-
-       u8 *raw_image;          // raw data captured from the camera
-       u8 *framebuf;           // processed data in RGB24 format
-       u8 *cntrlbuf;           // area used to send control msgs
-
-       struct video_device vdev;       // v4l video device
-       struct usb_device *udev;        // usb device
-
-       /* guard against simultaneous accesses to the camera */
-       struct mutex cam_lock;
-
-       int is_initialized;
-       u8 open_count;
-       u8 bulkEndpoint;
-       int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-       struct proc_dir_entry *proc_dir;
-#endif
-
-};
-
-static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
-static void vicam_disconnect(struct usb_interface *intf);
-static void read_frame(struct vicam_camera *cam, int framenum);
-static void vicam_decode_color(const u8 *, u8 *);
-
-static int __send_control_msg(struct vicam_camera *cam,
-                             u8 request,
-                             u16 value,
-                             u16 index,
-                             unsigned char *cp,
-                             u16 size)
-{
-       int status;
-
-       /* cp must be memory that has been allocated by kmalloc */
-
-       status = usb_control_msg(cam->udev,
-                                usb_sndctrlpipe(cam->udev, 0),
-                                request,
-                                USB_DIR_OUT | USB_TYPE_VENDOR |
-                                USB_RECIP_DEVICE, value, index,
-                                cp, size, 1000);
-
-       status = min(status, 0);
-
-       if (status < 0) {
-               printk(KERN_INFO "Failed sending control message, error %d.\n",
-                      status);
-       }
-
-       return status;
-}
-
-static int send_control_msg(struct vicam_camera *cam,
-                           u8 request,
-                           u16 value,
-                           u16 index,
-                           unsigned char *cp,
-                           u16 size)
-{
-       int status = -ENODEV;
-       mutex_lock(&cam->cam_lock);
-       if (cam->udev) {
-               status = __send_control_msg(cam, request, value,
-                                           index, cp, size);
-       }
-       mutex_unlock(&cam->cam_lock);
-       return status;
-}
-static int
-initialize_camera(struct vicam_camera *cam)
-{
-       const struct {
-               u8 *data;
-               u32 size;
-       } firmware[] = {
-               { .data = setup1, .size = sizeof(setup1) },
-               { .data = setup2, .size = sizeof(setup2) },
-               { .data = setup3, .size = sizeof(setup3) },
-               { .data = setup4, .size = sizeof(setup4) },
-               { .data = setup5, .size = sizeof(setup5) },
-               { .data = setup3, .size = sizeof(setup3) },
-               { .data = NULL, .size = 0 }
-       };
-
-       int err, i;
-
-       for (i = 0, err = 0; firmware[i].data && !err; i++) {
-               memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
-
-               err = send_control_msg(cam, 0xff, 0, 0,
-                                      cam->cntrlbuf, firmware[i].size);
-       }
-
-       return err;
-}
-
-static int
-set_camera_power(struct vicam_camera *cam, int state)
-{
-       int status;
-
-       if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
-               return status;
-
-       if (state) {
-               send_control_msg(cam, 0x55, 1, 0, NULL, 0);
-       }
-
-       return 0;
-}
-
-static int
-vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
-{
-       void __user *user_arg = (void __user *)arg;
-       struct vicam_camera *cam = file->private_data;
-       int retval = 0;
-
-       if (!cam)
-               return -ENODEV;
-
-       switch (ioctlnr) {
-               /* query capabilities */
-       case VIDIOCGCAP:
-               {
-                       struct video_capability b;
-
-                       DBG("VIDIOCGCAP\n");
-                       memset(&b, 0, sizeof(b));
-                       strcpy(b.name, "ViCam-based Camera");
-                       b.type = VID_TYPE_CAPTURE;
-                       b.channels = 1;
-                       b.audios = 0;
-                       b.maxwidth = 320;       /* VIDEOSIZE_CIF */
-                       b.maxheight = 240;
-                       b.minwidth = 320;       /* VIDEOSIZE_48_48 */
-                       b.minheight = 240;
-
-                       if (copy_to_user(user_arg, &b, sizeof(b)))
-                               retval = -EFAULT;
-
-                       break;
-               }
-               /* get/set video source - we are a camera and nothing else */
-       case VIDIOCGCHAN:
-               {
-                       struct video_channel v;
-
-                       DBG("VIDIOCGCHAN\n");
-                       if (copy_from_user(&v, user_arg, sizeof(v))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       if (v.channel != 0) {
-                               retval = -EINVAL;
-                               break;
-                       }
-
-                       v.channel = 0;
-                       strcpy(v.name, "Camera");
-                       v.tuners = 0;
-                       v.flags = 0;
-                       v.type = VIDEO_TYPE_CAMERA;
-                       v.norm = 0;
-
-                       if (copy_to_user(user_arg, &v, sizeof(v)))
-                               retval = -EFAULT;
-                       break;
-               }
-
-       case VIDIOCSCHAN:
-               {
-                       int v;
-
-                       if (copy_from_user(&v, user_arg, sizeof(v)))
-                               retval = -EFAULT;
-                       DBG("VIDIOCSCHAN %d\n", v);
-
-                       if (retval == 0 && v != 0)
-                               retval = -EINVAL;
-
-                       break;
-               }
-
-               /* image properties */
-       case VIDIOCGPICT:
-               {
-                       struct video_picture vp;
-                       DBG("VIDIOCGPICT\n");
-                       memset(&vp, 0, sizeof (struct video_picture));
-                       vp.brightness = cam->gain << 8;
-                       vp.depth = 24;
-                       vp.palette = VIDEO_PALETTE_RGB24;
-                       if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
-                               retval = -EFAULT;
-                       break;
-               }
-
-       case VIDIOCSPICT:
-               {
-                       struct video_picture vp;
-                       
-                       if (copy_from_user(&vp, user_arg, sizeof(vp))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       
-                       DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
-                           vp.palette);
-
-                       cam->gain = vp.brightness >> 8;
-
-                       if (vp.depth != 24
-                           || vp.palette != VIDEO_PALETTE_RGB24)
-                               retval = -EINVAL;
-
-                       break;
-               }
-
-               /* get/set capture window */
-       case VIDIOCGWIN:
-               {
-                       struct video_window vw;
-                       vw.x = 0;
-                       vw.y = 0;
-                       vw.width = 320;
-                       vw.height = 240;
-                       vw.chromakey = 0;
-                       vw.flags = 0;
-                       vw.clips = NULL;
-                       vw.clipcount = 0;
-
-                       DBG("VIDIOCGWIN\n");
-
-                       if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
-                               retval = -EFAULT;
-
-                       // I'm not sure what the deal with a capture window is, it is very poorly described
-                       // in the doc.  So I won't support it now.
-                       break;
-               }
-
-       case VIDIOCSWIN:
-               {
-
-                       struct video_window vw;
-
-                       if (copy_from_user(&vw, user_arg, sizeof(vw))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
-                       
-                       if ( vw.width != 320 || vw.height != 240 )
-                               retval = -EFAULT;
-
-                       break;
-               }
-
-               /* mmap interface */
-       case VIDIOCGMBUF:
-               {
-                       struct video_mbuf vm;
-                       int i;
-
-                       DBG("VIDIOCGMBUF\n");
-                       memset(&vm, 0, sizeof (vm));
-                       vm.size =
-                           VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
-                       vm.frames = VICAM_FRAMES;
-                       for (i = 0; i < VICAM_FRAMES; i++)
-                               vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
-
-                       if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
-                               retval = -EFAULT;
-
-                       break;
-               }
-
-       case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap vm;
-                       // int video_size;
-
-                       if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
-
-                       if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
-                               retval = -EINVAL;
-
-                       // in theory right here we'd start the image capturing
-                       // (fill in a bulk urb and submit it asynchronously)
-                       //
-                       // Instead we're going to do a total hack job for now and
-                       // retrieve the frame in VIDIOCSYNC
-
-                       break;
-               }
-
-       case VIDIOCSYNC:
-               {
-                       int frame;
-
-                       if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       DBG("VIDIOCSYNC: %d\n", frame);
-
-                       read_frame(cam, frame);
-                       vicam_decode_color(cam->raw_image,
-                                          cam->framebuf +
-                                          frame * VICAM_MAX_FRAME_SIZE );
-
-                       break;
-               }
-
-               /* pointless to implement overlay with this camera */
-       case VIDIOCCAPTURE:
-       case VIDIOCGFBUF:
-       case VIDIOCSFBUF:
-       case VIDIOCKEY:
-               retval = -EINVAL;
-               break;
-
-               /* tuner interface - we have none */
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               retval = -EINVAL;
-               break;
-
-               /* audio interface - we have none */
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               retval = -EINVAL;
-               break;
-       default:
-               retval = -ENOIOCTLCMD;
-               break;
-       }
-
-       return retval;
-}
-
-static int
-vicam_open(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct vicam_camera *cam =
-           (struct vicam_camera *) dev->priv;
-       DBG("open\n");
-
-       if (!cam) {
-               printk(KERN_ERR
-                      "vicam video_device improperly initialized");
-               return -EINVAL;
-       }
-
-       /* the videodev_lock held above us protects us from
-        * simultaneous opens...for now. we probably shouldn't
-        * rely on this fact forever.
-        */
-
-       if (cam->open_count > 0) {
-               printk(KERN_INFO
-                      "vicam_open called on already opened camera");
-               return -EBUSY;
-       }
-
-       cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
-       if (!cam->raw_image) {
-               return -ENOMEM;
-       }
-
-       cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-       if (!cam->framebuf) {
-               kfree(cam->raw_image);
-               return -ENOMEM;
-       }
-
-       cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!cam->cntrlbuf) {
-               kfree(cam->raw_image);
-               rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-               return -ENOMEM;
-       }
-
-       // First upload firmware, then turn the camera on
-
-       if (!cam->is_initialized) {
-               initialize_camera(cam);
-
-               cam->is_initialized = 1;
-       }
-
-       set_camera_power(cam, 1);
-
-       cam->needsDummyRead = 1;
-       cam->open_count++;
-
-       file->private_data = cam;       
-       
-       return 0;
-}
-
-static int 
-vicam_close(struct inode *inode, struct file *file)
-{
-       struct vicam_camera *cam = file->private_data;
-       int open_count;
-       struct usb_device *udev;
-
-       DBG("close\n");
-
-       /* it's not the end of the world if
-        * we fail to turn the camera off.
-        */
-
-       set_camera_power(cam, 0);
-
-       kfree(cam->raw_image);
-       rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-       kfree(cam->cntrlbuf);
-
-       mutex_lock(&cam->cam_lock);
-
-       cam->open_count--;
-       open_count = cam->open_count;
-       udev = cam->udev;
-
-       mutex_unlock(&cam->cam_lock);
-
-       if (!open_count && !udev) {
-               kfree(cam);
-       }
-
-       return 0;
-}
-
-static void vicam_decode_color(const u8 *data, u8 *rgb)
-{
-       /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
-        * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
-        */
-
-       int i, prevY, nextY;
-
-       prevY = 512;
-       nextY = 512;
-
-       data += VICAM_HEADER_SIZE;
-
-       for( i = 0; i < 240; i++, data += 512 ) {
-               const int y = ( i * 242 ) / 240;
-
-               int j, prevX, nextX;
-               int Y, Cr, Cb;
-
-               if ( y == 242 - 1 ) {
-                       nextY = -512;
-               }
-
-               prevX = 1;
-               nextX = 1;
-
-               for ( j = 0; j < 320; j++, rgb += 3 ) {
-                       const int x = ( j * 512 ) / 320;
-                       const u8 * const src = &data[x];
-
-                       if ( x == 512 - 1 ) {
-                               nextX = -1;
-                       }
-
-                       Cr = ( src[prevX] - src[0] ) +
-                               ( src[nextX] - src[0] );
-                       Cr /= 2;
-
-                       Cb = ( src[prevY] - src[prevX + prevY] ) +
-                               ( src[prevY] - src[nextX + prevY] ) +
-                               ( src[nextY] - src[prevX + nextY] ) +
-                               ( src[nextY] - src[nextX + nextY] );
-                       Cb /= 4;
-
-                       Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
-
-                       if ( i & 1 ) {
-                               int Ct = Cr;
-                               Cr = Cb;
-                               Cb = Ct;
-                       }
-
-                       if ( ( x ^ i ) & 1 ) {
-                               Cr = -Cr;
-                               Cb = -Cb;
-                       }
-
-                       rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
-                                       500 ) / 900, 0, 255 );
-                       rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
-                                         ( 813 * Cr ) ) +
-                                         500 ) / 1000, 0, 255 );
-                       rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
-                                       500 ) / 1300, 0, 255 );
-
-                       prevX = -1;
-               }
-
-               prevY = -512;
-       }
-}
-
-static void
-read_frame(struct vicam_camera *cam, int framenum)
-{
-       unsigned char *request = cam->cntrlbuf;
-       int realShutter;
-       int n;
-       int actual_length;
-
-       if (cam->needsDummyRead) {
-               cam->needsDummyRead = 0;
-               read_frame(cam, framenum);
-       }
-
-       memset(request, 0, 16);
-       request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
-
-       request[1] = 0; // 512x242 capture
-
-       request[2] = 0x90;      // the function of these two bytes
-       request[3] = 0x07;      // is not yet understood
-
-       if (cam->shutter_speed > 60) {
-               // Short exposure
-               realShutter =
-                   ((-15631900 / cam->shutter_speed) + 260533) / 1000;
-               request[4] = realShutter & 0xFF;
-               request[5] = (realShutter >> 8) & 0xFF;
-               request[6] = 0x03;
-               request[7] = 0x01;
-       } else {
-               // Long exposure
-               realShutter = 15600 / cam->shutter_speed - 1;
-               request[4] = 0;
-               request[5] = 0;
-               request[6] = realShutter & 0xFF;
-               request[7] = realShutter >> 8;
-       }
-
-       // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
-       request[8] = 0;
-       // bytes 9-15 do not seem to affect exposure or image quality
-
-       mutex_lock(&cam->cam_lock);
-
-       if (!cam->udev) {
-               goto done;
-       }
-
-       n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
-
-       if (n < 0) {
-               printk(KERN_ERR
-                      " Problem sending frame capture control message");
-               goto done;
-       }
-
-       n = usb_bulk_msg(cam->udev,
-                        usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
-                        cam->raw_image,
-                        512 * 242 + 128, &actual_length, 10000);
-
-       if (n < 0) {
-               printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
-                      n);
-       }
-
- done:
-       mutex_unlock(&cam->cam_lock);
-}
-
-static ssize_t
-vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
-{
-       struct vicam_camera *cam = file->private_data;
-
-       DBG("read %d bytes.\n", (int) count);
-
-       if (*ppos >= VICAM_MAX_FRAME_SIZE) {
-               *ppos = 0;
-               return 0;
-       }
-
-       if (*ppos == 0) {
-               read_frame(cam, 0);
-               vicam_decode_color(cam->raw_image,
-                                  cam->framebuf +
-                                  0 * VICAM_MAX_FRAME_SIZE);
-       }
-
-       count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
-
-       if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
-               count = -EFAULT;
-       } else {
-               *ppos += count;
-       }
-
-       if (count == VICAM_MAX_FRAME_SIZE) {
-               *ppos = 0;
-       }
-
-       return count;
-}
-
-
-static int
-vicam_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       // TODO: allocate the raw frame buffer if necessary
-       unsigned long page, pos;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       struct vicam_camera *cam = file->private_data;
-
-       if (!cam)
-               return -ENODEV;
-
-       DBG("vicam_mmap: %ld\n", size);
-
-       /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
-        * to the size the application requested for mmap and it was screwing apps up.
-        if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
-        return -EINVAL;
-        */
-
-       pos = (unsigned long)cam->framebuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
-                               int count, int *eof, int value)
-{
-       char *out = page;
-       int len;
-
-       out += sprintf(out, "%d",value);
-
-       len = out - page;
-       len -= off;
-       if (len < count) {
-               *eof = 1;
-               if (len <= 0)
-                       return 0;
-       } else
-               len = count;
-
-       *start = page + off;
-       return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
-                        unsigned long count, void *data)
-{
-       u16 stmp;
-       char kbuf[8];
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 6)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       stmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (stmp < 4 || stmp > 32000)
-               return -EINVAL;
-
-       cam->shutter_speed = stmp;
-
-       return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
-                     unsigned long count, void *data)
-{
-       u16 gtmp;
-       char kbuf[8];
-
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 4)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (gtmp > 255)
-               return -EINVAL;
-       cam->gain = gtmp;
-
-       return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
-       vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
-       if (vicam_proc_root)
-               vicam_proc_root->owner = THIS_MODULE;
-       else
-               printk(KERN_ERR
-                      "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
-       if (vicam_proc_root)
-               remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
-       char name[64];
-       struct proc_dir_entry *ent;
-
-       DBG(KERN_INFO "vicam: creating proc entry\n");
-
-       if (!vicam_proc_root || !cam) {
-               printk(KERN_INFO
-                      "vicam: could not create proc entry, %s pointer is null.\n",
-                      (!cam ? "camera" : "root"));
-               return;
-       }
-
-       sprintf(name, "video%d", cam->vdev.minor);
-
-       cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
-       if ( !cam->proc_dir )
-               return; // FIXME: We should probably return an error here
-       
-       ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_shutter;
-               ent->write_proc = vicam_write_proc_shutter;
-               ent->size = 64;
-       }
-
-       ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_gain;
-               ent->write_proc = vicam_write_proc_gain;
-               ent->size = 64;
-       }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
-       struct vicam_camera *cam = (struct vicam_camera *) ptr;
-       char name[16];
-
-       if ( !cam->proc_dir )
-               return;
-
-       sprintf(name, "video%d", cam->vdev.minor);
-       remove_proc_entry("shutter", cam->proc_dir);
-       remove_proc_entry("gain", cam->proc_dir);
-       remove_proc_entry(name,vicam_proc_root);
-       cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
-static struct file_operations vicam_fops = {
-       .owner          = THIS_MODULE,
-       .open           = vicam_open,
-       .release        = vicam_close,
-       .read           = vicam_read,
-       .mmap           = vicam_mmap,
-       .ioctl          = vicam_ioctl,
-       .compat_ioctl   = v4l_compat_ioctl32,
-       .llseek         = no_llseek,
-};
-
-static struct video_device vicam_template = {
-       .owner          = THIS_MODULE,
-       .name           = "ViCam-based USB Camera",
-       .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_VICAM,
-       .fops           = &vicam_fops,
-       .minor          = -1,
-};
-
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table[] = {
-       {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
-       {}                      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, vicam_table);
-
-static struct usb_driver vicam_driver = {
-       .name           = "vicam",
-       .probe          = vicam_probe,
-       .disconnect     = vicam_disconnect,
-       .id_table       = vicam_table
-};
-
-/**
- *     vicam_probe
- *     @intf: the interface
- *     @id: the device id
- *
- *     Called by the usb core when a new device is connected that it thinks
- *     this driver might be interested in.
- */
-static int
-vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       int bulkEndpoint = 0;
-       const struct usb_host_interface *interface;
-       const struct usb_endpoint_descriptor *endpoint;
-       struct vicam_camera *cam;
-       
-       printk(KERN_INFO "ViCam based webcam connected\n");
-
-       interface = intf->cur_altsetting;
-
-       DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
-              interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
-       endpoint = &interface->endpoint[0].desc;
-
-       if ((endpoint->bEndpointAddress & 0x80) &&
-           ((endpoint->bmAttributes & 3) == 0x02)) {
-               /* we found a bulk in endpoint */
-               bulkEndpoint = endpoint->bEndpointAddress;
-       } else {
-               printk(KERN_ERR
-                      "No bulk in endpoint was found ?! (this is bad)\n");
-       }
-
-       if ((cam =
-            kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
-               printk(KERN_WARNING
-                      "could not allocate kernel memory for vicam_camera struct\n");
-               return -ENOMEM;
-       }
-
-       memset(cam, 0, sizeof (struct vicam_camera));
-
-       cam->shutter_speed = 15;
-
-       mutex_init(&cam->cam_lock);
-
-       memcpy(&cam->vdev, &vicam_template,
-              sizeof (vicam_template));
-       cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
-
-       cam->udev = dev;
-       cam->bulkEndpoint = bulkEndpoint;
-
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
-               kfree(cam);
-               printk(KERN_WARNING "video_register_device failed\n");
-               return -EIO;
-       }
-
-       vicam_create_proc_entry(cam);
-
-       printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
-
-       usb_set_intfdata (intf, cam);
-       
-       return 0;
-}
-
-static void
-vicam_disconnect(struct usb_interface *intf)
-{
-       int open_count;
-       struct vicam_camera *cam = usb_get_intfdata (intf);
-       usb_set_intfdata (intf, NULL);
-
-       /* we must unregister the device before taking its
-        * cam_lock. This is because the video open call
-        * holds the same lock as video unregister. if we
-        * unregister inside of the cam_lock and open also
-        * uses the cam_lock, we get deadlock.
-        */
-
-       video_unregister_device(&cam->vdev);
-
-       /* stop the camera from being used */
-
-       mutex_lock(&cam->cam_lock);
-
-       /* mark the camera as gone */
-
-       cam->udev = NULL;
-
-       vicam_destroy_proc_entry(cam);
-
-       /* the only thing left to do is synchronize with
-        * our close/release function on who should release
-        * the camera memory. if there are any users using the
-        * camera, it's their job. if there are no users,
-        * it's ours.
-        */
-
-       open_count = cam->open_count;
-
-       mutex_unlock(&cam->cam_lock);
-
-       if (!open_count) {
-               kfree(cam);
-       }
-
-       printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
-}
-
-/*
- */
-static int __init
-usb_vicam_init(void)
-{
-       int retval;
-       DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
-       vicam_create_proc_root();
-       retval = usb_register(&vicam_driver);
-       if (retval)
-               printk(KERN_WARNING "usb_register failed!\n");
-       return retval;
-}
-
-static void __exit
-usb_vicam_exit(void)
-{
-       DBG(KERN_INFO
-              "ViCam-based WebCam driver shutdown\n");
-
-       usb_deregister(&vicam_driver);
-       vicam_destroy_proc_root();
-}
-
-module_init(usb_vicam_init);
-module_exit(usb_vicam_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
deleted file mode 100644 (file)
index b57dec3..0000000
+++ /dev/null
@@ -1,3691 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * - Memory management code from bttv driver by Ralph Metzler,             *
- *   Marcus Metzler and Gerd Knorr.                                        *
- * - I2C interface to kernel, high-level image sensor control routines and *
- *   some symbolic names from OV511 driver by Mark W. McClelland.          *
- * - Low-level I2C fast write function by Piotr Czerczak.                  *
- * - Low-level I2C read function by Frederic Jouault.                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <linux/page-flags.h>
-#include <linux/moduleparam.h>
-
-#include "w9968cf.h"
-#include "w9968cf_decoder.h"
-
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
-
-/****************************************************************************
- * Module macros and parameters                                             *
- ****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, winbond_id_table);
-
-MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
-MODULE_VERSION(W9968CF_MODULE_VERSION);
-MODULE_LICENSE(W9968CF_MODULE_LICENSE);
-MODULE_SUPPORTED_DEVICE("Video");
-
-static int ovmod_load = W9968CF_OVMOD_LOAD;
-static unsigned short simcams = W9968CF_SIMCAMS;
-static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
-static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                     W9968CF_PACKET_SIZE};
-static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                       W9968CF_BUFFERS};
-static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                              W9968CF_DOUBLE_BUFFER};
-static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
-static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                      W9968CF_FILTER_TYPE};
-static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
-static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                         W9968CF_DECOMPRESSION};
-static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
-static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
-static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
-static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
-static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
-static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                     W9968CF_LIGHTFREQ};
-static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
-                              W9968CF_BANDINGFILTER};
-static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
-static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
-static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
-static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                    W9968CF_BRIGHTNESS};
-static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
-static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
-static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                  W9968CF_CONTRAST};
-static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                   W9968CF_WHITENESS};
-#ifdef W9968CF_DEBUG
-static unsigned short debug = W9968CF_DEBUG_LEVEL;
-static int specific_debug = W9968CF_SPECIFIC_DEBUG;
-#endif
-
-static unsigned int param_nv[24]; /* number of values per parameter */
-
-#ifdef CONFIG_KMOD
-module_param(ovmod_load, bool, 0644);
-#endif
-module_param(simcams, ushort, 0644);
-module_param_array(video_nr, short, &param_nv[0], 0444);
-module_param_array(packet_size, uint, &param_nv[1], 0444);
-module_param_array(max_buffers, ushort, &param_nv[2], 0444);
-module_param_array(double_buffer, bool, &param_nv[3], 0444);
-module_param_array(clamping, bool, &param_nv[4], 0444);
-module_param_array(filter_type, ushort, &param_nv[5], 0444);
-module_param_array(largeview, bool, &param_nv[6], 0444);
-module_param_array(decompression, ushort, &param_nv[7], 0444);
-module_param_array(upscaling, bool, &param_nv[8], 0444);
-module_param_array(force_palette, ushort, &param_nv[9], 0444);
-module_param_array(force_rgb, ushort, &param_nv[10], 0444);
-module_param_array(autobright, bool, &param_nv[11], 0444);
-module_param_array(autoexp, bool, &param_nv[12], 0444);
-module_param_array(lightfreq, ushort, &param_nv[13], 0444);
-module_param_array(bandingfilter, bool, &param_nv[14], 0444);
-module_param_array(clockdiv, short, &param_nv[15], 0444);
-module_param_array(backlight, bool, &param_nv[16], 0444);
-module_param_array(mirror, bool, &param_nv[17], 0444);
-module_param_array(monochrome, bool, &param_nv[18], 0444);
-module_param_array(brightness, uint, &param_nv[19], 0444);
-module_param_array(hue, uint, &param_nv[20], 0444);
-module_param_array(colour, uint, &param_nv[21], 0444);
-module_param_array(contrast, uint, &param_nv[22], 0444);
-module_param_array(whiteness, uint, &param_nv[23], 0444);
-#ifdef W9968CF_DEBUG
-module_param(debug, ushort, 0644);
-module_param(specific_debug, bool, 0644);
-#endif
-
-#ifdef CONFIG_KMOD
-MODULE_PARM_DESC(ovmod_load, 
-                 "\n<0|1> Automatic 'ovcamchip' module loading."
-                 "\n0 disabled, 1 enabled."
-                 "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
-                 "\nmodule in the system, according to its configuration, and"
-                 "\nattempts to load that module automatically. This action is"
-                 "\nperformed once as soon as the 'w9968cf' module is loaded"
-                 "\ninto memory."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
-                 "\n");
-#endif
-MODULE_PARM_DESC(simcams, 
-                 "\n<n> Number of cameras allowed to stream simultaneously."
-                 "\nn may vary from 0 to "
-                 __MODULE_STRING(W9968CF_MAX_DEVICES)"."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
-                 "\n");
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
-                 " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-MODULE_PARM_DESC(packet_size,
-                 "\n<n[,...]> Specify the maximum data payload"
-                 "\nsize in bytes for alternate settings, for each device."
-                 "\nn is scaled between 63 and 1023 "
-                 "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
-                 "\n");
-MODULE_PARM_DESC(max_buffers,
-                 "\n<n[,...]> For advanced users."
-                 "\nSpecify the maximum number of video frame buffers"
-                 "\nto allocate for each device, from 2 to "
-                 __MODULE_STRING(W9968CF_MAX_BUFFERS)
-                 ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
-                 "\n");
-MODULE_PARM_DESC(double_buffer, 
-                 "\n<0|1[,...]> "
-                 "Hardware double buffering: 0 disabled, 1 enabled."
-                 "\nIt should be enabled if you want smooth video output: if"
-                 "\nyou obtain out of sync. video, disable it, or try to"
-                 "\ndecrease the 'clockdiv' module parameter value."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(clamping, 
-                 "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(filter_type, 
-                 "\n<0|1|2[,...]> Video filter type."
-                 "\n0 none, 1 (1-2-1) 3-tap filter, "
-                 "2 (2-3-6-3-2) 5-tap filter."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
-                 " for every device."
-                 "\nThe filter is used to reduce noise and aliasing artifacts"
-                 "\nproduced by the CCD or CMOS image sensor, and the scaling"
-                 " process."
-                 "\n");
-MODULE_PARM_DESC(largeview, 
-                 "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(upscaling, 
-                 "\n<0|1[,...]> Software scaling (for non-compressed video):"
-                 "\n0 disabled, 1 enabled."
-                 "\nDisable it if you have a slow CPU or you don't have"
-                 " enough memory."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
-                 " for every device."
-                 "\nIf 'w9968cf-vpp' is not present, this parameter is"
-                 " set to 0."
-                 "\n");
-MODULE_PARM_DESC(decompression,
-                 "\n<0|1|2[,...]> Software video decompression:"
-                 "\n- 0 disables decompression (doesn't allow formats needing"
-                 " decompression)"
-                 "\n- 1 forces decompression (allows formats needing"
-                 " decompression only);"
-                 "\n- 2 allows any permitted formats."
-                 "\nFormats supporting compressed video are YUV422P and"
-                 " YUV420P/YUV420 "
-                 "\nin any resolutions where both width and height are "
-                 "a multiple of 16."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
-                 " for every device."
-                 "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
-                 "\nnot allowed; in this case this parameter is set to 2."
-                 "\n");
-MODULE_PARM_DESC(force_palette,
-                 "\n<0"
-                 "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
-                 "[,...]>"
-                 " Force picture palette."
-                 "\nIn order:"
-                 "\n- 0 allows any of the following formats:"
-                 "\n- UYVY    16 bpp - Original video, compression disabled"
-                 "\n- YUV420  12 bpp - Original video, compression enabled"
-                 "\n- YUV422P 16 bpp - Original video, compression enabled"
-                 "\n- YUV420P 12 bpp - Original video, compression enabled"
-                 "\n- YUVY    16 bpp - Software conversion from UYVY"
-                 "\n- YUV422  16 bpp - Software conversion from UYVY"
-                 "\n- GREY     8 bpp - Software conversion from UYVY"
-                 "\n- RGB555  16 bpp - Software conversion from UYVY"
-                 "\n- RGB565  16 bpp - Software conversion from UYVY"
-                 "\n- RGB24   24 bpp - Software conversion from UYVY"
-                 "\n- RGB32   32 bpp - Software conversion from UYVY"
-                 "\nWhen not 0, this parameter will override 'decompression'."
-                 "\nDefault value is 0 for every device."
-                 "\nInitial palette is "
-                 __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
-                 "\nIf 'w9968cf-vpp' is not present, this parameter is"
-                 " set to 9 (UYVY)."
-                 "\n");
-MODULE_PARM_DESC(force_rgb, 
-                 "\n<0|1[,...]> Read RGB video data instead of BGR:"
-                 "\n 1 = use RGB component ordering."
-                 "\n 0 = use BGR component ordering."
-                 "\nThis parameter has effect when using RGBX palettes only."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(autobright,
-                 "\n<0|1[,...]> Image sensor automatically changes brightness:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(autoexp,
-                 "\n<0|1[,...]> Image sensor automatically changes exposure:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(lightfreq,
-                 "\n<50|60[,...]> Light frequency in Hz:"
-                 "\n 50 for European and Asian lighting,"
-                 " 60 for American lighting."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(bandingfilter,
-                 "\n<0|1[,...]> Banding filter to reduce effects of"
-                 " fluorescent lighting:"
-                 "\n 0 disabled, 1 enabled."
-                 "\nThis filter tries to reduce the pattern of horizontal"
-                 "\nlight/dark bands caused by some (usually fluorescent)"
-                 " lighting."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(clockdiv,
-                 "\n<-1|n[,...]> "
-                 "Force pixel clock divisor to a specific value (for experts):"
-                 "\n  n may vary from 0 to 127."
-                 "\n -1 for automatic value."
-                 "\nSee also the 'double_buffer' module parameter."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(backlight,
-                 "\n<0|1[,...]> Objects are lit from behind:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(mirror,
-                 "\n<0|1[,...]> Reverse image horizontally:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(monochrome,
-                 "\n<0|1[,...]> Use image sensor as monochrome sensor:"
-                 "\n 0 = no, 1 = yes"
-                 "\nNot all the sensors support monochrome color."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(brightness, 
-                 "\n<n[,...]> Set picture brightness (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
-                 " for every device."
-                 "\nThis parameter has no effect if 'autobright' is enabled."
-                 "\n");
-MODULE_PARM_DESC(hue, 
-                 "\n<n[,...]> Set picture hue (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(colour, 
-                 "\n<n[,...]> Set picture saturation (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(contrast, 
-                 "\n<n[,...]> Set picture contrast (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(whiteness, 
-                 "\n<n[,...]> Set picture whiteness (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
-                 " for every device."
-                 "\n");
-#ifdef W9968CF_DEBUG
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 6:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = configuration or general messages"
-                 "\n4 = warnings"
-                 "\n5 = called functions"
-                 "\n6 = function internals"
-                 "\nLevel 5 and 6 are useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
-                 "\n");
-MODULE_PARM_DESC(specific_debug,
-                 "\n<0|1> Enable or disable specific debugging messages:"
-                 "\n0 = print messages concerning every level"
-                 " <= 'debug' level."
-                 "\n1 = print messages concerning the level"
-                 " indicated by 'debug'."
-                 "\nDefault value is "
-                 __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
-                 "\n");
-#endif /* W9968CF_DEBUG */
-
-
-
-/****************************************************************************
- * Some prototypes                                                          *
- ****************************************************************************/
-
-/* Video4linux interface */
-static struct file_operations w9968cf_fops;
-static int w9968cf_open(struct inode*, struct file*);
-static int w9968cf_release(struct inode*, struct file*);
-static int w9968cf_mmap(struct file*, struct vm_area_struct*);
-static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);
-static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int,
-                             void __user *);
-
-/* USB-specific */
-static int w9968cf_start_transfer(struct w9968cf_device*);
-static int w9968cf_stop_transfer(struct w9968cf_device*);
-static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
-static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
-static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
-static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
-static int w9968cf_read_sb(struct w9968cf_device*);
-static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
-
-/* Low-level I2C (SMBus) I/O */
-static int w9968cf_smbus_start(struct w9968cf_device*);
-static int w9968cf_smbus_stop(struct w9968cf_device*);
-static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
-static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
-static int w9968cf_smbus_write_ack(struct w9968cf_device*);
-static int w9968cf_smbus_read_ack(struct w9968cf_device*);
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
-static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-                                      u16 address, u8* value);
-static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, 
-                                           u8 subaddress, u8* value);
-static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
-                                       u16 address, u8 subaddress);
-static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
-                                                u16 address, u8 subaddress,
-                                                u8 value);
-
-/* I2C interface to kernel */
-static int w9968cf_i2c_init(struct w9968cf_device*);
-static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, 
-                                  unsigned short flags, char read_write, 
-                                  u8 command, int size, union i2c_smbus_data*);
-static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
-static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
-                               unsigned long arg);
-
-/* Memory management */
-static void* rvmalloc(unsigned long size);
-static void rvfree(void *mem, unsigned long size);
-static void w9968cf_deallocate_memory(struct w9968cf_device*);
-static int  w9968cf_allocate_memory(struct w9968cf_device*);
-
-/* High-level image sensor control functions */
-static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
-static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
-static int w9968cf_sensor_cmd(struct w9968cf_device*,
-                              unsigned int cmd, void *arg);
-static int w9968cf_sensor_init(struct w9968cf_device*);
-static int w9968cf_sensor_update_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*);
-static int w9968cf_sensor_update_picture(struct w9968cf_device*, 
-                                         struct video_picture pict);
-
-/* Other helper functions */
-static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
-                                     enum w9968cf_model_id, 
-                                     const unsigned short dev_nr);
-static void w9968cf_adjust_configuration(struct w9968cf_device*);
-static int w9968cf_turn_on_led(struct w9968cf_device*);
-static int w9968cf_init_chip(struct w9968cf_device*);
-static inline u16 w9968cf_valid_palette(u16 palette);
-static inline u16 w9968cf_valid_depth(u16 palette);
-static inline u8 w9968cf_need_decompression(u16 palette);
-static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
-static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
-static int w9968cf_postprocess_frame(struct w9968cf_device*, 
-                                     struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
-static void w9968cf_init_framelist(struct w9968cf_device*);
-static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
-static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
-static void w9968cf_release_resources(struct w9968cf_device*);
-
-
-
-/****************************************************************************
- * Symbolic names                                                           *
- ****************************************************************************/
-
-/* Used to represent a list of values and their respective symbolic names */
-struct w9968cf_symbolic_list {
-       const int num;
-       const char *name;
-};
-
-/*-------------------------------------------------------------------------- 
-  Returns the name of the matching element in the symbolic_list array. The
-  end of the list must be marked with an element that has a NULL name.
-  --------------------------------------------------------------------------*/
-static inline const char * 
-symbolic(struct w9968cf_symbolic_list list[], const int num)
-{
-       int i;
-
-       for (i = 0; list[i].name != NULL; i++)
-               if (list[i].num == num)
-                       return (list[i].name);
-
-       return "Unknown";
-}
-
-static struct w9968cf_symbolic_list camlist[] = {
-       { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
-       { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
-
-       /* Other cameras (having the same descriptors as Generic W996[87]CF) */
-       { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
-       { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
-       { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
-       { W9968CF_MOD_LL, "Lebon LDC-035A" },
-       { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
-       { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
-       { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
-       { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
-       { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
-
-       {  -1, NULL }
-};
-
-static struct w9968cf_symbolic_list senlist[] = {
-       { CC_OV76BE,   "OV76BE" },
-       { CC_OV7610,   "OV7610" },
-       { CC_OV7620,   "OV7620" },
-       { CC_OV7620AE, "OV7620AE" },
-       { CC_OV6620,   "OV6620" },
-       { CC_OV6630,   "OV6630" },
-       { CC_OV6630AE, "OV6630AE" },
-       { CC_OV6630AF, "OV6630AF" },
-       { -1, NULL }
-};
-
-/* Video4Linux1 palettes */
-static struct w9968cf_symbolic_list v4l1_plist[] = {
-       { VIDEO_PALETTE_GREY,    "GREY" },
-       { VIDEO_PALETTE_HI240,   "HI240" },
-       { VIDEO_PALETTE_RGB565,  "RGB565" },
-       { VIDEO_PALETTE_RGB24,   "RGB24" },
-       { VIDEO_PALETTE_RGB32,   "RGB32" },
-       { VIDEO_PALETTE_RGB555,  "RGB555" },
-       { VIDEO_PALETTE_YUV422,  "YUV422" },
-       { VIDEO_PALETTE_YUYV,    "YUYV" },
-       { VIDEO_PALETTE_UYVY,    "UYVY" },
-       { VIDEO_PALETTE_YUV420,  "YUV420" },
-       { VIDEO_PALETTE_YUV411,  "YUV411" },
-       { VIDEO_PALETTE_RAW,     "RAW" },
-       { VIDEO_PALETTE_YUV422P, "YUV422P" },
-       { VIDEO_PALETTE_YUV411P, "YUV411P" },
-       { VIDEO_PALETTE_YUV420P, "YUV420P" },
-       { VIDEO_PALETTE_YUV410P, "YUV410P" },
-       { -1, NULL }
-};
-
-/* Decoder error codes: */
-static struct w9968cf_symbolic_list decoder_errlist[] = {
-       { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
-       { W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
-       { W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },     
-       { W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
-       { W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
-       { W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
-       { -1, NULL }
-};
-
-/* URB error codes: */
-static struct w9968cf_symbolic_list urb_errlist[] = {
-       { -ENOMEM,    "No memory for allocation of internal structures" },
-       { -ENOSPC,    "The host controller's bandwidth is already consumed" },
-       { -ENOENT,    "URB was canceled by unlink_urb" },
-       { -EXDEV,     "ISO transfer only partially completed" },
-       { -EAGAIN,    "Too match scheduled for the future" },
-       { -ENXIO,     "URB already queued" },
-       { -EFBIG,     "Too much ISO frames requested" },
-       { -ENOSR,     "Buffer error (overrun)" },
-       { -EPIPE,     "Specified endpoint is stalled (device not responding)"},
-       { -EOVERFLOW, "Babble (bad cable?)" },
-       { -EPROTO,    "Bit-stuff error (bad cable?)" },
-       { -EILSEQ,    "CRC/Timeout" },
-       { -ETIMEDOUT, "NAK (device does not respond)" },
-       { -1, NULL }
-};
-
-
-
-/****************************************************************************
- * Memory management functions                                              *
- ****************************************************************************/
-static void* rvmalloc(unsigned long size)
-{
-       void* mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-
-static void rvfree(void* mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-
-/*--------------------------------------------------------------------------
-  Deallocate previously allocated memory.
-  --------------------------------------------------------------------------*/
-static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
-{
-       u8 i;
-
-       /* Free the isochronous transfer buffers */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               kfree(cam->transfer_buffer[i]);
-               cam->transfer_buffer[i] = NULL;
-       }
-
-       /* Free temporary frame buffer */
-       if (cam->frame_tmp.buffer) {
-               rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
-               cam->frame_tmp.buffer = NULL;
-       }
-
-       /* Free helper buffer */
-       if (cam->frame_vpp.buffer) {
-               rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
-               cam->frame_vpp.buffer = NULL;
-       }
-
-       /* Free video frame buffers */
-       if (cam->frame[0].buffer) {
-               rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
-               cam->frame[0].buffer = NULL;
-       }
-
-       cam->nbuffers = 0;
-
-       DBG(5, "Memory successfully deallocated")
-}
-
-
-/*--------------------------------------------------------------------------
-  Allocate memory buffers for USB transfers and video frames.
-  This function is called by open() only.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_allocate_memory(struct w9968cf_device* cam)
-{
-       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-       void* buff = NULL;
-       unsigned long hw_bufsize, vpp_bufsize;
-       u8 i, bpp;
-
-       /* NOTE: Deallocation is done elsewhere in case of error */
-
-       /* Calculate the max amount of raw data per frame from the device */
-       hw_bufsize = cam->maxwidth*cam->maxheight*2;
-
-       /* Calculate the max buf. size needed for post-processing routines */
-       bpp = (w9968cf_vpp) ? 4 : 2;
-       if (cam->upscaling)
-               vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
-                                 cam->maxwidth*cam->maxheight*bpp);
-       else
-               vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
-
-       /* Allocate memory for the isochronous transfer buffers */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               if (!(cam->transfer_buffer[i] =
-                     kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
-                       DBG(1, "Couldn't allocate memory for the isochronous "
-                              "transfer buffers (%u bytes)", 
-                           p_size * W9968CF_ISO_PACKETS)
-                       return -ENOMEM;
-               }
-       }
-
-       /* Allocate memory for the temporary frame buffer */
-       if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
-               DBG(1, "Couldn't allocate memory for the temporary "
-                      "video frame buffer (%lu bytes)", hw_bufsize)
-               return -ENOMEM;
-       }
-       cam->frame_tmp.size = hw_bufsize;
-       cam->frame_tmp.number = -1;
-
-       /* Allocate memory for the helper buffer */
-       if (w9968cf_vpp) {
-               if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
-                       DBG(1, "Couldn't allocate memory for the helper buffer"
-                              " (%lu bytes)", vpp_bufsize)
-                       return -ENOMEM;
-               }
-               cam->frame_vpp.size = vpp_bufsize;
-       } else
-               cam->frame_vpp.buffer = NULL;
-
-       /* Allocate memory for video frame buffers */
-       cam->nbuffers = cam->max_buffers;
-       while (cam->nbuffers >= 2) {
-               if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
-                       break;
-               else
-                       cam->nbuffers--;
-       }
-
-       if (!buff) {
-               DBG(1, "Couldn't allocate memory for the video frame buffers")
-               cam->nbuffers = 0;
-               return -ENOMEM;
-       }
-
-       if (cam->nbuffers != cam->max_buffers)
-               DBG(2, "Couldn't allocate memory for %u video frame buffers. "
-                      "Only memory for %u buffers has been allocated",
-                   cam->max_buffers, cam->nbuffers)
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].buffer = buff + i*vpp_bufsize;
-               cam->frame[i].size = vpp_bufsize;
-               cam->frame[i].number = i;
-               /* Circular list */
-               if (i != cam->nbuffers-1)
-                       cam->frame[i].next = &cam->frame[i+1];
-               else
-                       cam->frame[i].next = &cam->frame[0];
-               cam->frame[i].status = F_UNUSED;
-       }
-
-       DBG(5, "Memory successfully allocated")
-       return 0;
-}
-
-
-
-/****************************************************************************
- * USB-specific functions                                                   *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This is an handler function which is called after the URBs are completed.
-  It collects multiple data packets coming from the camera by putting them
-  into frame buffers: one or more zero data length data packets are used to
-  mark the end of a video frame; the first non-zero data packet is the start
-  of the next video frame; if an error is encountered in a packet, the entire
-  video frame is discarded and grabbed again.
-  If there are no requested frames in the FIFO list, packets are collected into
-  a temporary buffer. 
-  --------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
-{
-       struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
-       struct w9968cf_frame_t** f;
-       unsigned int len, status;
-       void* pos;
-       u8 i;
-       int err = 0;
-
-       if ((!cam->streaming) || cam->disconnected) {
-               DBG(4, "Got interrupt, but not streaming")
-               return;
-       }
-
-       /* "(*f)" will be used instead of "cam->frame_current" */
-       f = &cam->frame_current;
-
-       /* If a frame has been requested and we are grabbing into  
-          the temporary frame, we'll switch to that requested frame */
-       if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
-               if (cam->frame_tmp.status == F_GRABBING) {
-                       w9968cf_pop_frame(cam, &cam->frame_current);
-                       (*f)->status = F_GRABBING;
-                       (*f)->length = cam->frame_tmp.length;
-                       memcpy((*f)->buffer, cam->frame_tmp.buffer,
-                              (*f)->length);
-                       DBG(6, "Switched from temp. frame to frame #%d", 
-                           (*f)->number)
-               }
-       }
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status && len != 0) {
-                       DBG(4, "URB failed, error in data packet "
-                              "(error #%u, %s)",
-                           status, symbolic(urb_errlist, status))
-                       (*f)->status = F_ERROR;
-                       continue;
-               }
-
-               if (len) { /* start of frame */
-
-                       if ((*f)->status == F_UNUSED) {
-                               (*f)->status = F_GRABBING;
-                               (*f)->length = 0;
-                       }
-
-                       /* Buffer overflows shouldn't happen, however...*/
-                       if ((*f)->length + len > (*f)->size) {
-                               DBG(4, "Buffer overflow: bad data packets")
-                               (*f)->status = F_ERROR;
-                       }
-
-                       if ((*f)->status == F_GRABBING) {
-                               memcpy((*f)->buffer + (*f)->length, pos, len);
-                               (*f)->length += len;
-                       }
-
-               } else if ((*f)->status == F_GRABBING) { /* end of frame */
-
-                       DBG(6, "Frame #%d successfully grabbed", (*f)->number)
-
-                       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-                               err = w9968cf_vpp->check_headers((*f)->buffer,
-                                                                (*f)->length);
-                               if (err) {
-                                       DBG(4, "Skip corrupted frame: %s",
-                                           symbolic(decoder_errlist, err))
-                                       (*f)->status = F_UNUSED;
-                                       continue; /* grab this frame again */
-                               }
-                       }
-
-                       (*f)->status = F_READY;
-                       (*f)->queued = 0;
-
-                       /* Take a pointer to the new frame from the FIFO list.
-                          If the list is empty,we'll use the temporary frame*/
-                       if (*cam->requested_frame)
-                               w9968cf_pop_frame(cam, &cam->frame_current);
-                       else {
-                               cam->frame_current = &cam->frame_tmp;
-                               (*f)->status = F_UNUSED;
-                       }
-
-               } else if ((*f)->status == F_ERROR)
-                       (*f)->status = F_UNUSED; /* grab it again */
-
-               PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
-                     (unsigned long)(*f)->length, i, len, (*f)->status)
-
-       } /* end for */
-
-       /* Resubmit this URB */
-       urb->dev = cam->usbdev;
-       urb->status = 0;
-       spin_lock(&cam->urb_lock);
-       if (cam->streaming)
-               if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
-                       cam->misconfigured = 1;
-                       DBG(1, "Couldn't resubmit the URB: error %d, %s",
-                           err, symbolic(urb_errlist, err))
-               }
-       spin_unlock(&cam->urb_lock);
-
-       /* Wake up the user process */
-       wake_up_interruptible(&cam->wait_queue);
-}
-
-
-/*---------------------------------------------------------------------------
-  Setup the URB structures for the isochronous transfer.
-  Submit the URBs so that the data transfer begins.
-  Return 0 on success, a negative number otherwise.
-  ---------------------------------------------------------------------------*/
-static int w9968cf_start_transfer(struct w9968cf_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-       u16 w, h, d;
-       int vidcapt;
-       u32 t_size;
-       int err = 0;
-       s8 i, j;
-
-       for (i = 0; i < W9968CF_URBS; i++) {
-               urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       for (j = 0; j < i; j++)
-                               usb_free_urb(cam->urb[j]);
-                       DBG(1, "Couldn't allocate the URB structures")
-                       return -ENOMEM;
-               }
-
-               urb->dev = udev;
-               urb->context = (void*)cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = W9968CF_ISO_PACKETS;
-               urb->complete = w9968cf_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = p_size*j;
-                       urb->iso_frame_desc[j].length = p_size;
-               }
-       }
-
-       /* Transfer size per frame, in WORD ! */
-       d = cam->hw_depth;
-       w = cam->hw_width;
-       h = cam->hw_height;
-
-       t_size = (w*h*d)/16;
-
-       err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-
-       /* Transfer size */
-       err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
-       err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION)
-               err += w9968cf_upload_quantizationtables(cam);
-
-       vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
-       err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
-
-       err += usb_set_interface(udev, 0, cam->altsetting);
-       err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
-
-       if (err || (vidcapt < 0)) {
-               for (i = 0; i < W9968CF_URBS; i++)
-                       usb_free_urb(cam->urb[i]);
-               DBG(1, "Couldn't tell the camera to start the data transfer")
-               return err;
-       }
-
-       w9968cf_init_framelist(cam);
-
-       /* Begin to grab into the temporary buffer */
-       cam->frame_tmp.status = F_UNUSED;
-       cam->frame_tmp.queued = 0;
-       cam->frame_current = &cam->frame_tmp;
-
-       if (!(cam->vpp_flag & VPP_DECOMPRESSION))
-               DBG(5, "Isochronous transfer size: %lu bytes/frame", 
-                   (unsigned long)t_size*2)
-
-       DBG(5, "Starting the isochronous transfer...")
-
-       cam->streaming = 1;
-
-       /* Submit the URBs */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       cam->streaming = 0;
-                       for (j = i-1; j >= 0; j--) {
-                               usb_kill_urb(cam->urb[j]);
-                               usb_free_urb(cam->urb[j]);
-                       }
-                       DBG(1, "Couldn't send a transfer request to the "
-                              "USB core (error #%d, %s)", err, 
-                           symbolic(urb_errlist, err))
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_stop_transfer(struct w9968cf_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       unsigned long lock_flags;
-       int err = 0;
-       s8 i;
-
-       if (!cam->streaming)
-               return 0;
-
-       /* This avoids race conditions with usb_submit_urb() 
-          in the URB completition handler */
-       spin_lock_irqsave(&cam->urb_lock, lock_flags);
-       cam->streaming = 0;
-       spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
-
-       for (i = W9968CF_URBS-1; i >= 0; i--)
-               if (cam->urb[i]) {
-                       usb_kill_urb(cam->urb[i]);
-                       usb_free_urb(cam->urb[i]);
-                       cam->urb[i] = NULL;
-               }
-
-       if (cam->disconnected)
-               goto exit;
-
-       err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
-       err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
-       err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
-
-       if (err) {
-               DBG(2, "Failed to tell the camera to stop the isochronous "
-                      "transfer. However this is not a critical error.")
-               return -EIO;
-       }
-
-exit:
-       DBG(5, "Isochronous transfer stopped")
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write a W9968CF register. 
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       int res;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-                             value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to write a register "
-                      "(value 0x%04X, index 0x%02X, error #%d, %s)",
-                   value, index, res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read a W9968CF register. 
-  Return the register value on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u16* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
-                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to read a register "
-                      "(index 0x%02X, error #%d, %s)",
-                   index, res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write 64-bit data to the fast serial bus registers.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
-{
-       struct usb_device* udev = cam->usbdev;
-       u16 value;
-       int res;
-
-       value = *data++;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-                             value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to write the FSB registers "
-                      "(error #%d, %s)", res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write data to the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
-{
-       int err = 0;
-
-       err = w9968cf_write_reg(cam, value, 0x01);
-       udelay(W9968CF_I2C_BUS_DELAY);
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read data from the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_sb(struct w9968cf_device* cam)
-{
-       int v = 0;
-
-       v = w9968cf_read_reg(cam, 0x01);
-       udelay(W9968CF_I2C_BUS_DELAY);
-
-       return v;
-}
-
-
-/*--------------------------------------------------------------------------
-  Upload quantization tables for the JPEG compression.
-  This function is called by w9968cf_start_transfer().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
-{
-       u16 a, b;
-       int err = 0, i, j;
-
-       err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
-
-       for (i = 0, j = 0; i < 32; i++, j += 2) {
-               a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
-               b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
-               err += w9968cf_write_reg(cam, a, 0x40+i);
-               err += w9968cf_write_reg(cam, b, 0x60+i);
-       }
-       err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
-
-       return err;
-}
-
-
-
-/****************************************************************************
- * Low-level I2C I/O functions.                                             *
- * The adapter supports the following I2C transfer functions:               *
- * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
- * i2c_adap_read_byte_data()                                                *
- * i2c_adap_read_byte()                                                     *
- ****************************************************************************/
-
-static int w9968cf_smbus_start(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_stop(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
-{
-       u8 bit;
-       int err = 0, sda;
-
-       for (bit = 0 ; bit < 8 ; bit++) {
-               sda = (v & 0x80) ? 2 : 0;
-               v <<= 1;
-               /* SDE=1, SDA=sda, SCL=0 */
-               err += w9968cf_write_sb(cam, 0x10 | sda);
-               /* SDE=1, SDA=sda, SCL=1 */
-               err += w9968cf_write_sb(cam, 0x11 | sda);
-               /* SDE=1, SDA=sda, SCL=0 */
-               err += w9968cf_write_sb(cam, 0x10 | sda);
-       }
-
-       return err;
-}
-
-
-static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
-{
-       u8 bit;
-       int err = 0;
-
-       *v = 0;
-       for (bit = 0 ; bit < 8 ; bit++) {
-               *v <<= 1;
-               err += w9968cf_write_sb(cam, 0x0013);
-               *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
-               err += w9968cf_write_sb(cam, 0x0012);
-       }
-
-       return err;
-}
-
-
-static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
-{
-       int err = 0, sda;
-
-       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-       sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
-       err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
-       if (sda < 0)
-               err += sda;
-       if (sda == 1) {
-               DBG(6, "Couldn't receive the ACK")
-               err += -1;
-       }
-
-       return err;
-}
-
-
-/* This seems to refresh the communication through the serial bus */
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
-{
-       int err = 0, j;
-
-       for (j = 1; j <= 10; j++) {
-               err = w9968cf_write_reg(cam, 0x0020, 0x01);
-               err += w9968cf_write_reg(cam, 0x0000, 0x01);
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int 
-w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, 
-                                     u16 address, u8 subaddress,u8 value)
-{
-       u16* data = cam->data_buffer;
-       int err = 0;
-
-       err += w9968cf_smbus_refresh_bus(cam);
-
-       /* Enable SBUS outputs */
-       err += w9968cf_write_sb(cam, 0x0020);
-
-       data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
-       data[0] |= (address & 0x40) ? 0x4000 : 0x0;
-       data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
-       data[1] |= (address & 0x20) ? 0x0150 : 0x0;
-       data[1] |= (address & 0x10) ? 0x5400 : 0x0;
-       data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
-       data[2] |= (address & 0x04) ? 0x0540 : 0x0;
-       data[2] |= (address & 0x02) ? 0x5000 : 0x0;
-       data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
-       data[3] |= (address & 0x01) ? 0x0054 : 0x0;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
-       data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
-       data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
-       data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
-       data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
-       data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
-       data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
-       data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
-       data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
-       data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
-       data[3] = 0x001d;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
-       data[0] |= (value & 0x40) ? 0x0540 : 0x0;
-       data[0] |= (value & 0x20) ? 0x5000 : 0x0;
-       data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
-       data[1] |= (value & 0x10) ? 0x0054 : 0x0;
-       data[1] |= (value & 0x08) ? 0x1500 : 0x0;
-       data[1] |= (value & 0x04) ? 0x4000 : 0x0;
-       data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
-       data[2] |= (value & 0x02) ? 0x0150 : 0x0;
-       data[2] |= (value & 0x01) ? 0x5400 : 0x0;
-       data[3] = 0xfe1d;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       /* Disable SBUS outputs */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
-                      "value 0x%02X", address, subaddress, value)
-       else
-               DBG(5, "I2C write byte data failed, addr.0x%04X, "
-                      "subaddr.0x%02X, value 0x%02X", 
-                   address, subaddress, value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
-static int 
-w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, 
-                                u16 address, u8 subaddress, 
-                                u8* value)
-{
-       int err = 0;
-
-       /* Serial data enable */
-       err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
-
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_write_byte(cam, subaddress);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address + 1);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_read_byte(cam, value);
-       err += w9968cf_smbus_write_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-
-       /* Serial data disable */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C read byte data done, addr.0x%04X, "
-                      "subaddr.0x%02X, value 0x%02X", 
-                   address, subaddress, *value)
-       else
-               DBG(5, "I2C read byte data failed, addr.0x%04X, "
-                      "subaddr.0x%02X, wrong value 0x%02X",
-                   address, subaddress, *value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
-static int 
-w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-                           u16 address, u8* value)
-{
-       int err = 0;
-
-       /* Serial data enable */
-       err += w9968cf_write_sb(cam, 0x0013);
-
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address + 1);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_read_byte(cam, value);
-       err += w9968cf_smbus_write_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-       /* Serial data disable */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C read byte done, addr.0x%04X, "
-                      "value 0x%02X", address, *value)
-       else
-               DBG(5, "I2C read byte failed, addr.0x%04X, "
-                      "wrong value 0x%02X", address, *value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Value [A] P */
-static int 
-w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
-                            u16 address, u8 value)
-{
-       DBG(4, "i2c_write_byte() is an unsupported transfer mode")
-       return -EINVAL;
-}
-
-
-
-/****************************************************************************
- * I2C interface to kernel                                                  *
- ****************************************************************************/
-
-static int
-w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 
-                       unsigned short flags, char read_write, u8 command,
-                       int size, union i2c_smbus_data *data)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(adapter);
-       u8 i;
-       int err = 0; 
-
-       switch (addr) {
-               case OV6xx0_SID:
-               case OV7xx0_SID:
-                       break;
-               default:
-                       DBG(4, "Rejected slave ID 0x%04X", addr)
-                       return -EINVAL;
-       }
-
-       if (size == I2C_SMBUS_BYTE) {
-               /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
-               addr <<= 1;
-
-               if (read_write == I2C_SMBUS_WRITE)
-                       err = w9968cf_i2c_adap_write_byte(cam, addr, command);
-               else if (read_write == I2C_SMBUS_READ) 
-                       err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
-       } else if (size == I2C_SMBUS_BYTE_DATA) {
-               addr <<= 1;
-
-               if (read_write == I2C_SMBUS_WRITE)
-                       err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
-                                                         command, data->byte);
-               else if (read_write == I2C_SMBUS_READ) {
-                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-                               err = w9968cf_i2c_adap_read_byte_data(cam,addr,
-                                                        command, &data->byte);
-                               if (err) {
-                                       if (w9968cf_smbus_refresh_bus(cam)) {
-                                               err = -EIO;
-                                               break;
-                                       }
-                               } else
-                                       break;
-                       }
-
-               } else
-                       return -EINVAL;
-
-       } else {
-               DBG(4, "Unsupported I2C transfer mode (%d)", size)
-               return -EINVAL;
-       }
-
-       return err;
-}
-
-
-static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
-{
-       return I2C_FUNC_SMBUS_READ_BYTE |
-              I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-       int id = client->driver->id, err = 0;
-
-       if (id == I2C_DRIVERID_OVCAMCHIP) {
-               cam->sensor_client = client;
-               err = w9968cf_sensor_init(cam);
-               if (err) {
-                       cam->sensor_client = NULL;
-                       return err;
-               }
-       } else {
-               DBG(4, "Rejected client [%s] with driver [%s]", 
-                   client->name, client->driver->driver.name)
-               return -EINVAL;
-       }
-
-       DBG(5, "I2C attach client [%s] with driver [%s]",
-           client->name, client->driver->driver.name)
-
-       return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
-       if (cam->sensor_client == client)
-               cam->sensor_client = NULL;
-
-       DBG(5, "I2C detach client [%s]", client->name)
-
-       return 0;
-}
-
-
-static int 
-w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
-                    unsigned long arg)
-{
-       return 0;
-}
-
-
-static int w9968cf_i2c_init(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       static struct i2c_algorithm algo = {
-               .smbus_xfer =    w9968cf_i2c_smbus_xfer,
-               .algo_control =  w9968cf_i2c_control,
-               .functionality = w9968cf_i2c_func,
-       };
-
-       static struct i2c_adapter adap = {
-               .id =                I2C_HW_SMBUS_W9968CF,
-               .class =             I2C_CLASS_CAM_DIGITAL,
-               .owner =             THIS_MODULE,
-               .client_register =   w9968cf_i2c_attach_inform,
-               .client_unregister = w9968cf_i2c_detach_inform,
-               .algo =              &algo,
-       };
-
-       memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
-       strcpy(cam->i2c_adapter.name, "w9968cf");
-       i2c_set_adapdata(&cam->i2c_adapter, cam);
-
-       DBG(6, "Registering I2C adapter with kernel...")
-
-       err = i2c_add_adapter(&cam->i2c_adapter);
-       if (err)
-               DBG(1, "Failed to register the I2C adapter")
-       else
-               DBG(5, "I2C adapter registered")
-
-       return err;
-}
-
-
-
-/****************************************************************************
- * Helper functions                                                         *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  Turn on the LED on some webcams. A beep should be heard too.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_turn_on_led(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
-       err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
-       err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
-       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
-
-       if (err)
-               DBG(2, "Couldn't turn on the LED")
-
-       DBG(5, "LED turned on")
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write some registers for the device initialization.
-  This function is called once on open().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_init_chip(struct w9968cf_device* cam)
-{
-       unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
-                     y0 = 0x0000,
-                     u0 = y0 + hw_bufsize/2,
-                     v0 = u0 + hw_bufsize/4,
-                     y1 = v0 + hw_bufsize/4,
-                     u1 = y1 + hw_bufsize/2,
-                     v1 = u1 + hw_bufsize/4;
-       int err = 0;
-
-       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
-
-       err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
-       err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
-
-       err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
-       err += w9968cf_write_reg(cam, y0 >> 16, 0x21);    /* Y buf.0, high */
-       err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
-       err += w9968cf_write_reg(cam, u0 >> 16, 0x25);    /* U buf.0, high */
-       err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
-       err += w9968cf_write_reg(cam, v0 >> 16, 0x29);    /* V buf.0, high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x23);    /* Y buf.1, high */
-       err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
-       err += w9968cf_write_reg(cam, u1 >> 16, 0x27);    /* U buf.1, high */
-       err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
-       err += w9968cf_write_reg(cam, v1 >> 16, 0x2b);    /* V buf.1, high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x33);    /* JPEG buf 0 high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x35);    /* JPEG bug 1 high */
-
-       err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
-       err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
-       err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
-       err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
-
-       err += w9968cf_set_picture(cam, cam->picture); /* this before */
-       err += w9968cf_set_window(cam, cam->window);
-
-       if (err)
-               DBG(1, "Chip initialization failed")
-       else
-               DBG(5, "Chip successfully initialized")
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the palette is supported, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_palette(u16 palette)
-{
-       u8 i = 0;
-       while (w9968cf_formatlist[i].palette != 0) {
-               if (palette == w9968cf_formatlist[i].palette)
-                       return palette;
-               i++;
-       }
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return the depth corresponding to the given palette.
-  Palette _must_ be supported !
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_depth(u16 palette)
-{
-       u8 i=0;
-       while (w9968cf_formatlist[i].palette != palette)
-               i++;
-
-       return w9968cf_formatlist[i].depth;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the format requires decompression, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u8 w9968cf_need_decompression(u16 palette)
-{
-       u8 i = 0;
-       while (w9968cf_formatlist[i].palette != 0) {
-               if (palette == w9968cf_formatlist[i].palette)
-                       return w9968cf_formatlist[i].compression;
-               i++;
-       }
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the picture settings of the camera.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
-{
-       u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
-       int err = 0;
-
-       /* Make sure we are using a valid depth */
-       pict.depth = w9968cf_valid_depth(pict.palette);
-
-       fmt = pict.palette;
-
-       hw_depth = pict.depth; /* depth used by the winbond chip */
-       hw_palette = pict.palette; /* palette used by the winbond chip */
-
-       /* VS & HS polarities */
-       reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
-
-       switch (fmt)
-       {
-               case VIDEO_PALETTE_UYVY:
-                       reg_v |= 0x0000;
-                       cam->vpp_flag = VPP_NONE;
-                       break;
-               case VIDEO_PALETTE_YUV422P:
-                       reg_v |= 0x0002;
-                       cam->vpp_flag = VPP_DECOMPRESSION;
-                       break;
-               case VIDEO_PALETTE_YUV420:
-               case VIDEO_PALETTE_YUV420P:
-                       reg_v |= 0x0003;
-                       cam->vpp_flag = VPP_DECOMPRESSION;
-                       break;
-               case VIDEO_PALETTE_YUYV:
-               case VIDEO_PALETTE_YUV422:
-                       reg_v |= 0x0000;
-                       cam->vpp_flag = VPP_SWAP_YUV_BYTES;
-                       hw_palette = VIDEO_PALETTE_UYVY;
-                       break;
-               /* Original video is used instead of RGBX palettes. 
-                  Software conversion later. */
-               case VIDEO_PALETTE_GREY:
-               case VIDEO_PALETTE_RGB555:
-               case VIDEO_PALETTE_RGB565:
-               case VIDEO_PALETTE_RGB24:
-               case VIDEO_PALETTE_RGB32:
-                       reg_v |= 0x0000; /* UYVY 16 bit is used */
-                       hw_depth = 16;
-                       hw_palette = VIDEO_PALETTE_UYVY;
-                       cam->vpp_flag = VPP_UYVY_TO_RGBX;
-                       break;
-       }
-
-       /* NOTE: due to memory issues, it is better to disable the hardware
-                double buffering during compression */
-       if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
-               reg_v |= 0x0080;
-
-       if (cam->clamping)
-               reg_v |= 0x0020;
-
-       if (cam->filter_type == 1)
-               reg_v |= 0x0008;
-       else if (cam->filter_type == 2)
-               reg_v |= 0x000c;
-
-       if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
-               goto error;
-
-       if ((err = w9968cf_sensor_update_picture(cam, pict)))
-               goto error;
-
-       /* If all went well, update the device data structure */
-       memcpy(&cam->picture, &pict, sizeof(pict));
-       cam->hw_depth = hw_depth;
-       cam->hw_palette = hw_palette;
-
-       /* Settings changed, so we clear the frame buffers */
-       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-       DBG(4, "Palette is %s, depth is %u bpp",
-           symbolic(v4l1_plist, pict.palette), pict.depth)
-
-       return 0;
-
-error:
-       DBG(1, "Failed to change picture settings")
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the capture area size of the camera.
-  This function _must_ be called _after_ w9968cf_set_picture().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
-{
-       u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
-       unsigned long fw, fh;
-       struct ovcamchip_window s_win;
-       int err = 0;
-
-       /* Work around to avoid FP arithmetics */
-       #define __SC(x) ((x) << 10)
-       #define __UNSC(x) ((x) >> 10)
-
-       /* Make sure we are using a supported resolution */
-       if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, 
-                                             (u16*)&win.height)))
-               goto error;
-
-       /* Scaling factors */
-       fw = __SC(win.width) / cam->maxwidth;
-       fh = __SC(win.height) / cam->maxheight;
-
-       /* Set up the width and height values used by the chip */
-       if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
-               cam->vpp_flag |= VPP_UPSCALE;
-               /* Calculate largest w,h mantaining the same w/h ratio */
-               w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
-               h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
-               if (w < cam->minwidth) /* just in case */
-                       w = cam->minwidth;
-               if (h < cam->minheight) /* just in case */
-                       h = cam->minheight;
-       } else {
-               cam->vpp_flag &= ~VPP_UPSCALE;
-               w = win.width;
-               h = win.height;
-       }
-
-       /* x,y offsets of the cropped area */
-       scx = cam->start_cropx;
-       scy = cam->start_cropy;
-
-       /* Calculate cropped area manteining the right w/h ratio */
-       if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
-               cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
-               ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
-       } else {
-               cw = w;
-               ch = h;
-       }
-
-       /* Setup the window of the sensor */
-       s_win.format = VIDEO_PALETTE_UYVY;
-       s_win.width = cam->maxwidth;
-       s_win.height = cam->maxheight;
-       s_win.quarter = 0; /* full progressive video */
-
-       /* Center it */
-       s_win.x = (s_win.width - cw) / 2;
-       s_win.y = (s_win.height - ch) / 2;
-
-       /* Clock divisor */
-       if (cam->clockdiv >= 0)
-               s_win.clockdiv = cam->clockdiv; /* manual override */
-       else
-               switch (cam->sensor) {
-                       case CC_OV6620:
-                               s_win.clockdiv = 0;
-                               break;
-                       case CC_OV6630:
-                               s_win.clockdiv = 0;
-                               break;
-                       case CC_OV76BE:
-                       case CC_OV7610:
-                       case CC_OV7620:
-                               s_win.clockdiv = 0;
-                               break;
-                       default:
-                               s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
-               }
-
-       /* We have to scale win.x and win.y offsets */
-       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-            || (cam->vpp_flag & VPP_UPSCALE) ) {
-               ax = __SC(win.x)/fw;
-               ay = __SC(win.y)/fh;
-       } else {
-               ax = win.x;
-               ay = win.y;
-       }
-
-       if ((ax + cw) > cam->maxwidth)
-               ax = cam->maxwidth - cw;
-
-       if ((ay + ch) > cam->maxheight)
-               ay = cam->maxheight - ch;
-
-       /* Adjust win.x, win.y */
-       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-            || (cam->vpp_flag & VPP_UPSCALE) ) {
-               win.x = __UNSC(ax*fw);
-               win.y = __UNSC(ay*fh);
-       } else {
-               win.x = ax;
-               win.y = ay;
-       }
-
-       /* Offsets used by the chip */
-       x = ax + s_win.x;
-       y = ay + s_win.y;
-
-       /* Go ! */
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
-               goto error;
-
-       err += w9968cf_write_reg(cam, scx + x, 0x10);
-       err += w9968cf_write_reg(cam, scy + y, 0x11);
-       err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
-       err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
-       err += w9968cf_write_reg(cam, w, 0x14);
-       err += w9968cf_write_reg(cam, h, 0x15);
-
-       /* JPEG width & height */
-       err += w9968cf_write_reg(cam, w, 0x30);
-       err += w9968cf_write_reg(cam, h, 0x31);
-
-       /* Y & UV frame buffer strides (in WORD) */
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               err += w9968cf_write_reg(cam, w/2, 0x2c);
-               err += w9968cf_write_reg(cam, w/4, 0x2d);
-       } else
-               err += w9968cf_write_reg(cam, w, 0x2c);
-
-       if (err)
-               goto error;
-
-       /* If all went well, update the device data structure */
-       memcpy(&cam->window, &win, sizeof(win));
-       cam->hw_width = w;
-       cam->hw_height = h;
-
-       /* Settings changed, so we clear the frame buffers */
-       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-       DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", 
-           win.width, win.height, win.x, win.y)
-
-       PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
-             "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
-             x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
-             win.width, win.height)
-
-       return 0;
-
-error:
-       DBG(1, "Failed to change the capture area size")
-       return err;
-}
-
-
-/*-------------------------------------------------------------------------- 
-  Adjust the asked values for window width and height.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int 
-w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
-{
-       u16 maxw, maxh;
-
-       if ((*width < cam->minwidth) || (*height < cam->minheight))
-               return -ERANGE;
-
-       maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-              w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
-                          : cam->maxwidth;
-       maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-              w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-                          : cam->maxheight;
-
-       if (*width > maxw)
-               *width = maxw;
-       if (*height > maxh)
-               *height = maxh;
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               *width  &= ~15L; /* multiple of 16 */
-               *height &= ~15L;
-       }
-
-       PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Initialize the FIFO list of requested frames.
-  --------------------------------------------------------------------------*/
-static void w9968cf_init_framelist(struct w9968cf_device* cam)
-{
-       u8 i;
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->requested_frame[i] = NULL;
-               cam->frame[i].queued = 0;
-               cam->frame[i].status = F_UNUSED;
-       }
-}
-
-
-/*--------------------------------------------------------------------------
-  Add a frame in the FIFO list of requested frames.
-  This function is called in process context.
-  --------------------------------------------------------------------------*/
-static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
-{
-       u8 f;
-       unsigned long lock_flags;
-
-       spin_lock_irqsave(&cam->flist_lock, lock_flags);
-
-       for (f=0; cam->requested_frame[f] != NULL; f++);
-       cam->requested_frame[f] = &cam->frame[f_num];
-       cam->frame[f_num].queued = 1;
-       cam->frame[f_num].status = F_UNUSED; /* clear the status */
-
-       spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
-
-       DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
-}
-
-
-/*--------------------------------------------------------------------------
-  Read, store and remove the first pointer in the FIFO list of requested
-  frames. This function is called in interrupt context.
-  --------------------------------------------------------------------------*/
-static void 
-w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
-{
-       u8 i;
-
-       spin_lock(&cam->flist_lock);
-
-       *framep = cam->requested_frame[0];
-
-       /* Shift the list of pointers */
-       for (i = 0; i < cam->nbuffers-1; i++)
-               cam->requested_frame[i] = cam->requested_frame[i+1];
-       cam->requested_frame[i] = NULL;
-
-       spin_unlock(&cam->flist_lock);
-
-       DBG(6,"Popped frame #%d from the list", (*framep)->number)
-}
-
-
-/*--------------------------------------------------------------------------
-  High-level video post-processing routine on grabbed frames.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int 
-w9968cf_postprocess_frame(struct w9968cf_device* cam, 
-                          struct w9968cf_frame_t* fr)
-{
-       void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
-       u16 w = cam->window.width,
-           h = cam->window.height,
-           d = cam->picture.depth,
-           fmt = cam->picture.palette,
-           rgb = cam->force_rgb,
-           hw_w = cam->hw_width,
-           hw_h = cam->hw_height,
-           hw_d = cam->hw_depth;
-       int err = 0;
-
-       #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               memcpy(pOut, pIn, fr->length);
-               _PSWAP(pIn, pOut)
-               err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
-               PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
-               fr->length = (hw_w*hw_h*hw_d)/8;
-               _PSWAP(pIn, pOut)
-               if (err) {
-                       DBG(4, "An error occurred while decoding the frame: "
-                              "%s", symbolic(decoder_errlist, err))
-                       return err;
-               } else
-                       DBG(6, "Frame decoded")
-       }
-
-       if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
-               w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
-               DBG(6, "Original UYVY component ordering changed")
-       }
-
-       if (cam->vpp_flag & VPP_UPSCALE) {
-               w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
-               fr->length = (w*h*hw_d)/8;
-               _PSWAP(pIn, pOut)
-               DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
-                   hw_w, hw_h, hw_d, w, h)
-       }
-
-       if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
-               w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
-               fr->length = (w*h*d)/8;
-               _PSWAP(pIn, pOut)
-               DBG(6, "UYVY-16bit to %s conversion done", 
-                   symbolic(v4l1_plist, fmt))
-       }
-
-       if (pOut == fr->buffer)
-               memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
-
-       return 0;
-}
-
-
-
-/****************************************************************************
- * Image sensor control routines                                            *
- ****************************************************************************/
-
-static int 
-w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
-{
-       struct ovcamchip_control ctl;
-       int err;
-
-       ctl.id = cid;
-       ctl.value = val;
-
-       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
-
-       return err;
-}
-
-
-static int 
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
-{
-       struct ovcamchip_control ctl;
-       int err;
-
-       ctl.id = cid;
-
-       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
-       if (!err)
-               *val = ctl.value;
-
-       return err;
-}
-
-
-static int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
-{
-       struct i2c_client* c = cam->sensor_client;
-       int rc = 0;
-
-       if (!c || !c->driver || !c->driver->command)
-               return -EINVAL;
-
-       rc = c->driver->command(c, cmd, arg);
-       /* The I2C driver returns -EPERM on non-supported controls */
-       return (rc < 0 && rc != -EPERM) ? rc : 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update some settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       /* Auto brightness */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, 
-                                        cam->auto_brt);
-       if (err)
-               return err;
-
-       /* Auto exposure */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, 
-                                        cam->auto_exp);
-       if (err)
-               return err;
-
-       /* Banding filter */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, 
-                                        cam->bandfilt);
-       if (err)
-               return err;
-
-       /* Light frequency */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
-                                        cam->lightfreq);
-       if (err)
-               return err;
-
-       /* Back light */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
-                                        cam->backlight);
-       if (err)
-               return err;
-
-       /* Mirror */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
-                                        cam->mirror);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Get some current picture settings from the image sensor and update the
-  internal 'picture' structure of the camera.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
-{
-       int err, v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
-       if (err)
-               return err;
-       cam->picture.contrast = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
-       if (err)
-               return err;
-       cam->picture.brightness = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
-       if (err)
-               return err;
-       cam->picture.colour = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
-       if (err)
-               return err;
-       cam->picture.hue = v;
-
-       DBG(5, "Got picture settings from the image sensor")
-
-       PDBGG("Brightness, contrast, hue, colour, whiteness are "
-             "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
-             cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update picture settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_update_picture(struct w9968cf_device* cam, 
-                              struct video_picture pict)
-{
-       int err = 0;
-
-       if ((!cam->sensor_initialized)
-           || pict.contrast != cam->picture.contrast) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
-                                                pict.contrast);
-               if (err)
-                       goto fail;
-               DBG(4, "Contrast changed from %u to %u",
-                   cam->picture.contrast, pict.contrast)
-               cam->picture.contrast = pict.contrast;
-       }
-
-       if (((!cam->sensor_initialized) || 
-           pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, 
-                                                pict.brightness);
-               if (err)
-                       goto fail;
-               DBG(4, "Brightness changed from %u to %u",
-                   cam->picture.brightness, pict.brightness)
-               cam->picture.brightness = pict.brightness;
-       }
-
-       if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, 
-                                                pict.colour);
-               if (err)
-                       goto fail;
-               DBG(4, "Colour changed from %u to %u",
-                   cam->picture.colour, pict.colour)
-               cam->picture.colour = pict.colour;
-       }
-
-       if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, 
-                                                pict.hue);
-               if (err)
-                       goto fail;
-               DBG(4, "Hue changed from %u to %u",
-                   cam->picture.hue, pict.hue)
-               cam->picture.hue = pict.hue;
-       }
-
-       return 0;
-
-fail:
-       DBG(4, "Failed to change sensor picture setting")
-       return err;
-}
-
-
-
-/****************************************************************************
- * Camera configuration                                                     *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This function is called when a supported image sensor is detected.
-  Return 0 if the initialization succeeds, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_init(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, 
-                                     &cam->monochrome)))
-               goto error;
-
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, 
-                                     &cam->sensor)))
-               goto error;
-
-       /* NOTE: Make sure width and height are a multiple of 16 */
-       switch (cam->sensor_client->addr) {
-               case OV6xx0_SID:
-                       cam->maxwidth = 352;
-                       cam->maxheight = 288;
-                       cam->minwidth = 64;
-                       cam->minheight = 48;
-                       break;
-               case OV7xx0_SID:
-                       cam->maxwidth = 640;
-                       cam->maxheight = 480;
-                       cam->minwidth = 64;
-                       cam->minheight = 48;
-                       break;
-               default:
-                       DBG(1, "Not supported image sensor detected for %s",
-                           symbolic(camlist, cam->id))
-                       return -EINVAL;
-       }
-
-       /* These values depend on the ones in the ovxxx0.c sources */
-       switch (cam->sensor) {
-               case CC_OV7620:
-                       cam->start_cropx = 287;
-                       cam->start_cropy = 35;
-                       /* Seems to work around a bug in the image sensor */
-                       cam->vs_polarity = 1;
-                       cam->hs_polarity = 1;
-                       break;
-               default:
-                       cam->start_cropx = 320;
-                       cam->start_cropy = 35;
-                       cam->vs_polarity = 1;
-                       cam->hs_polarity = 0;
-       }
-
-       if ((err = w9968cf_sensor_update_settings(cam)))
-               goto error;
-
-       if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
-               goto error;
-
-       cam->sensor_initialized = 1;
-
-       DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
-       return 0;
-
-error:
-       cam->sensor_initialized = 0;
-       cam->sensor = CC_UNKNOWN;
-       DBG(1, "Image sensor initialization failed for %s (/dev/video%d). "
-              "Try to detach and attach this device again",
-           symbolic(camlist, cam->id), cam->v4ldev->minor)
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Fill some basic fields in the main device data structure.
-  This function is called once on w9968cf_usb_probe() for each recognized 
-  camera.
-  --------------------------------------------------------------------------*/
-static void
-w9968cf_configure_camera(struct w9968cf_device* cam,
-                         struct usb_device* udev,
-                         enum w9968cf_model_id mod_id,
-                         const unsigned short dev_nr)
-{
-       mutex_init(&cam->fileop_mutex);
-       init_waitqueue_head(&cam->open);
-       spin_lock_init(&cam->urb_lock);
-       spin_lock_init(&cam->flist_lock);
-
-       cam->users = 0;
-       cam->disconnected = 0;
-       cam->id = mod_id;
-       cam->sensor = CC_UNKNOWN;
-       cam->sensor_initialized = 0;
-
-       /* Calculate the alternate setting number (from 1 to 16)
-          according to the 'packet_size' module parameter */
-       if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
-               packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
-       for (cam->altsetting = 1;
-            packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
-            cam->altsetting++);
-
-       cam->max_buffers = (max_buffers[dev_nr] < 2 || 
-                           max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
-                          ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
-
-       cam->double_buffer = (double_buffer[dev_nr] == 0 || 
-                             double_buffer[dev_nr] == 1)
-                            ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
-
-       cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
-                       ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
-       
-       cam->filter_type = (filter_type[dev_nr] == 0 ||
-                           filter_type[dev_nr] == 1 ||
-                           filter_type[dev_nr] == 2)
-                          ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
-
-       cam->capture = 1;
-
-       cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
-                        ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
-
-       cam->decompression = (decompression[dev_nr] == 0 || 
-                             decompression[dev_nr] == 1 ||
-                             decompression[dev_nr] == 2)
-                            ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
-
-       cam->upscaling = (upscaling[dev_nr] == 0 || 
-                         upscaling[dev_nr] == 1)
-                        ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
-
-       cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
-                       ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
-
-       cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
-                       ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
-
-       cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
-                        ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
-
-       cam->bandfilt = (bandingfilter[dev_nr] == 0 || 
-                        bandingfilter[dev_nr] == 1)
-                       ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
-
-       cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
-                        ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
-
-       cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
-                       ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
-
-       cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
-                     ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
-
-       cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
-                         ? monochrome[dev_nr] : W9968CF_MONOCHROME;
-
-       cam->picture.brightness = (u16)brightness[dev_nr];
-       cam->picture.hue = (u16)hue[dev_nr];
-       cam->picture.colour = (u16)colour[dev_nr];
-       cam->picture.contrast = (u16)contrast[dev_nr];
-       cam->picture.whiteness = (u16)whiteness[dev_nr];
-       if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
-               cam->picture.palette = (u16)force_palette[dev_nr];
-               cam->force_palette = 1;
-       } else {
-               cam->force_palette = 0;
-               if (cam->decompression == 0)
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
-               else if (cam->decompression == 1)
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
-               else
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
-       }
-       cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-
-       cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
-                        ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
-
-       cam->window.x = 0;
-       cam->window.y = 0;
-       cam->window.width = W9968CF_WIDTH;
-       cam->window.height = W9968CF_HEIGHT;
-       cam->window.chromakey = 0;
-       cam->window.clipcount = 0;
-       cam->window.flags = 0;
-
-       DBG(3, "%s configured with settings #%u:",
-           symbolic(camlist, cam->id), dev_nr)
-       
-       DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
-           wMaxPacketSize[cam->altsetting-1])
-       
-       DBG(3, "- Number of requested video frame buffers: %u",
-           cam->max_buffers)
-
-       if (cam->double_buffer)
-               DBG(3, "- Hardware double buffering enabled")
-       else 
-               DBG(3, "- Hardware double buffering disabled")
-
-       if (cam->filter_type == 0)
-               DBG(3, "- Video filtering disabled")
-       else if (cam->filter_type == 1)
-               DBG(3, "- Video filtering enabled: type 1-2-1")
-       else if (cam->filter_type == 2)
-               DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
-
-       if (cam->clamping)
-               DBG(3, "- Video data clamping (CCIR-601 format) enabled")
-       else
-               DBG(3, "- Video data clamping (CCIR-601 format) disabled")
-
-       if (cam->largeview)
-               DBG(3, "- Large view enabled")
-       else
-               DBG(3, "- Large view disabled")
-
-       if ((cam->decompression) == 0 && (!cam->force_palette))
-               DBG(3, "- Decompression disabled")
-       else if ((cam->decompression) == 1 && (!cam->force_palette))
-               DBG(3, "- Decompression forced")
-       else if ((cam->decompression) == 2 && (!cam->force_palette))
-               DBG(3, "- Decompression allowed")
-
-       if (cam->upscaling)
-               DBG(3, "- Software image scaling enabled")
-       else
-               DBG(3, "- Software image scaling disabled")
-
-       if (cam->force_palette)
-               DBG(3, "- Image palette forced to %s",
-                   symbolic(v4l1_plist, cam->picture.palette))
-
-       if (cam->force_rgb)
-               DBG(3, "- RGB component ordering will be used instead of BGR")
-
-       if (cam->auto_brt)
-               DBG(3, "- Auto brightness enabled")
-       else
-               DBG(3, "- Auto brightness disabled")
-
-       if (cam->auto_exp)
-               DBG(3, "- Auto exposure enabled")
-       else
-               DBG(3, "- Auto exposure disabled")
-
-       if (cam->backlight)
-               DBG(3, "- Backlight exposure algorithm enabled")
-       else
-               DBG(3, "- Backlight exposure algorithm disabled")
-
-       if (cam->mirror)
-               DBG(3, "- Mirror enabled")
-       else
-               DBG(3, "- Mirror disabled")
-
-       if (cam->bandfilt)
-               DBG(3, "- Banding filter enabled")
-       else
-               DBG(3, "- Banding filter disabled")
-
-       DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
-
-       if (cam->clockdiv == -1)
-               DBG(3, "- Automatic clock divisor enabled")
-       else
-               DBG(3, "- Clock divisor: %d", cam->clockdiv)
-
-       if (cam->monochrome)
-               DBG(3, "- Image sensor used as monochrome")
-       else
-               DBG(3, "- Image sensor not used as monochrome")
-}
-
-
-/*--------------------------------------------------------------------------
-  If the video post-processing module is not loaded, some parameters
-  must be overridden.
-  --------------------------------------------------------------------------*/
-static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
-{
-       if (!w9968cf_vpp) {
-               if (cam->decompression == 1) {
-                       cam->decompression = 2;
-                       DBG(2, "Video post-processing module not found: "
-                              "'decompression' parameter forced to 2")
-               }
-               if (cam->upscaling) {
-                       cam->upscaling = 0;
-                       DBG(2, "Video post-processing module not found: "
-                              "'upscaling' parameter forced to 0")
-               }
-               if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
-                       cam->force_palette = 0;
-                       DBG(2, "Video post-processing module not found: "
-                              "'force_palette' parameter forced to 0")
-               }
-               cam->picture.palette = VIDEO_PALETTE_UYVY;
-               cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-       }
-}
-
-
-/*--------------------------------------------------------------------------
-  Release the resources used by the driver.
-  This function is called on disconnect 
-  (or on close if deallocation has been deferred)
-  --------------------------------------------------------------------------*/
-static void w9968cf_release_resources(struct w9968cf_device* cam)
-{
-       mutex_lock(&w9968cf_devlist_mutex);
-
-       DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
-
-       video_unregister_device(cam->v4ldev);
-       list_del(&cam->v4llist);
-       i2c_del_adapter(&cam->i2c_adapter);
-       w9968cf_deallocate_memory(cam);
-       kfree(cam->control_buffer);
-       kfree(cam->data_buffer);
-
-       mutex_unlock(&w9968cf_devlist_mutex);
-}
-
-
-
-/****************************************************************************
- * Video4Linux interface                                                    *
- ****************************************************************************/
-
-static int w9968cf_open(struct inode* inode, struct file* filp)
-{
-       struct w9968cf_device* cam;
-       int err;
-
-       /* This the only safe way to prevent race conditions with disconnect */
-       if (!down_read_trylock(&w9968cf_disconnect))
-               return -ERESTARTSYS;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex);
-
-       if (cam->sensor == CC_UNKNOWN) {
-               DBG(2, "No supported image sensor has been detected by the "
-                      "'ovcamchip' module for the %s (/dev/video%d). Make "
-                      "sure it is loaded *before* (re)connecting the camera.",
-                   symbolic(camlist, cam->id), cam->v4ldev->minor)
-               mutex_unlock(&cam->dev_mutex);
-               up_read(&w9968cf_disconnect);
-               return -ENODEV;
-       }
-
-       if (cam->users) {
-               DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
-                   symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
-               if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
-                       mutex_unlock(&cam->dev_mutex);
-                       up_read(&w9968cf_disconnect);
-                       return -EWOULDBLOCK;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                        cam->disconnected ||
-                                                        !cam->users);
-               if (err) {
-                       up_read(&w9968cf_disconnect);
-                       return err;
-               }
-               if (cam->disconnected) {
-                       up_read(&w9968cf_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-       DBG(5, "Opening '%s', /dev/video%d ...",
-           symbolic(camlist, cam->id), cam->v4ldev->minor)
-
-       cam->streaming = 0;
-       cam->misconfigured = 0;
-
-       w9968cf_adjust_configuration(cam);
-
-       if ((err = w9968cf_allocate_memory(cam)))
-               goto deallocate_memory;
-
-       if ((err = w9968cf_init_chip(cam)))
-               goto deallocate_memory;
-
-       if ((err = w9968cf_start_transfer(cam)))
-               goto deallocate_memory;
-
-       filp->private_data = cam;
-
-       cam->users++;
-       strcpy(cam->command, current->comm);
-
-       init_waitqueue_head(&cam->wait_queue);
-
-       DBG(5, "Video device is open")
-
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&w9968cf_disconnect);
-
-       return 0;
-
-deallocate_memory:
-       w9968cf_deallocate_memory(cam);
-       DBG(2, "Failed to open the video device")
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&w9968cf_disconnect);
-       return err;
-}
-
-
-static int w9968cf_release(struct inode* inode, struct file* filp)
-{
-       struct w9968cf_device* cam;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       w9968cf_stop_transfer(cam);
-
-       if (cam->disconnected) {
-               w9968cf_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       w9968cf_deallocate_memory(cam);
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(5, "Video device closed")
-       mutex_unlock(&cam->dev_mutex);
-       return 0;
-}
-
-
-static ssize_t
-w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct w9968cf_device* cam;
-       struct w9968cf_frame_t* fr;
-       int err = 0;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       if (filp->f_flags & O_NONBLOCK)
-               return -EWOULDBLOCK;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again.")
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (!cam->frame[0].queued)
-               w9968cf_push_frame(cam, 0);
-
-       if (!cam->frame[1].queued)
-               w9968cf_push_frame(cam, 1);
-
-       err = wait_event_interruptible(cam->wait_queue,
-                                      cam->frame[0].status == F_READY ||
-                                      cam->frame[1].status == F_READY ||
-                                      cam->disconnected);
-       if (err) {
-               mutex_unlock(&cam->fileop_mutex);
-               return err;
-       }
-       if (cam->disconnected) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
-
-       if (w9968cf_vpp)
-               w9968cf_postprocess_frame(cam, fr);
-
-       if (count > fr->length)
-               count = fr->length;
-
-       if (copy_to_user(buf, fr->buffer, count)) {
-               fr->status = F_UNUSED;
-               mutex_unlock(&cam->fileop_mutex);
-               return -EFAULT;
-       }
-       *f_pos += count;
-
-       fr->status = F_UNUSED;
-
-       DBG(5, "%zu bytes read", count)
-
-       mutex_unlock(&cam->fileop_mutex);
-       return count;
-}
-
-
-static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct w9968cf_device* cam = (struct w9968cf_device*)
-                                    video_get_drvdata(video_devdata(filp));
-       unsigned long vsize = vma->vm_end - vma->vm_start,
-                     psize = cam->nbuffers * cam->frame[0].size,
-                     start = vma->vm_start,
-                     pos = (unsigned long)cam->frame[0].buffer,
-                     page;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again")
-               return -EIO;
-       }
-
-       PDBGG("mmapping %lu bytes...", vsize)
-
-       if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
-               return -EINVAL;
-
-       while (vsize > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
-                                               PAGE_SIZE, vma->vm_page_prot))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               vsize -= PAGE_SIZE;
-       }
-
-       DBG(5, "mmap method successfully called")
-       return 0;
-}
-
-
-static int
-w9968cf_ioctl(struct inode* inode, struct file* filp,
-              unsigned int cmd, unsigned long arg)
-{
-       struct w9968cf_device* cam;
-       int err;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again.")
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-       return err;
-}
-
-
-static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
-                             unsigned int cmd, void __user * arg)
-{
-       struct w9968cf_device* cam;
-       const char* v4l1_ioctls[] = {
-               "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", 
-               "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
-               "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
-               "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
-               "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", 
-               "GVBIFMT", "SVBIFMT" 
-       };
-
-       #define V4L1_IOCTL(cmd) \
-               ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
-               v4l1_ioctls[_IOC_NR((cmd))] : "?")
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOCGCAP: /* get video capability */
-       {
-               struct video_capability cap = {
-                       .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
-                       .channels = 1,
-                       .audios = 0,
-                       .minwidth = cam->minwidth,
-                       .minheight = cam->minheight,
-               };
-               sprintf(cap.name, "W996[87]CF USB Camera #%d", 
-                       cam->v4ldev->minor);
-               cap.maxwidth = (cam->upscaling && w9968cf_vpp)
-                              ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) 
-                                : cam->maxwidth;
-               cap.maxheight = (cam->upscaling && w9968cf_vpp)
-                               ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-                                 : cam->maxheight;
-
-               if (copy_to_user(arg, &cap, sizeof(cap)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGCAP successfully called")
-               return 0;
-       }
-
-       case VIDIOCGCHAN: /* get video channel informations */
-       {
-               struct video_channel chan;
-               if (copy_from_user(&chan, arg, sizeof(chan)))
-                       return -EFAULT;
-
-               if (chan.channel != 0)
-                       return -EINVAL;
-
-               strcpy(chan.name, "Camera");
-               chan.tuners = 0;
-               chan.flags = 0;
-               chan.type = VIDEO_TYPE_CAMERA;
-               chan.norm = VIDEO_MODE_AUTO;
-
-               if (copy_to_user(arg, &chan, sizeof(chan)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGCHAN successfully called")
-               return 0;
-       }
-
-       case VIDIOCSCHAN: /* set active channel */
-       {
-               struct video_channel chan;
-
-               if (copy_from_user(&chan, arg, sizeof(chan)))
-                       return -EFAULT;
-
-               if (chan.channel != 0)
-                       return -EINVAL;
-
-               DBG(5, "VIDIOCSCHAN successfully called")
-               return 0;
-       }
-
-       case VIDIOCGPICT: /* get image properties of the picture */
-       {
-               if (w9968cf_sensor_get_picture(cam))
-                       return -EIO;
-
-               if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGPICT successfully called")
-               return 0;
-       }
-
-       case VIDIOCSPICT: /* change picture settings */
-       {
-               struct video_picture pict;
-               int err = 0;
-
-               if (copy_from_user(&pict, arg, sizeof(pict)))
-                       return -EFAULT;
-
-               if ( (cam->force_palette || !w9968cf_vpp) 
-                    && pict.palette != cam->picture.palette ) {
-                       DBG(4, "Palette %s rejected: only %s is allowed",
-                           symbolic(v4l1_plist, pict.palette),
-                           symbolic(v4l1_plist, cam->picture.palette))
-                       return -EINVAL;
-               }
-
-               if (!w9968cf_valid_palette(pict.palette)) {
-                       DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
-                           symbolic(v4l1_plist, pict.palette))
-                       return -EINVAL;
-               }
-
-               if (!cam->force_palette) {
-                  if (cam->decompression == 0) {
-                     if (w9968cf_need_decompression(pict.palette)) {
-                        DBG(4, "Decompression disabled: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, pict.palette))
-                        return -EINVAL;
-                     }
-                  } else if (cam->decompression == 1) {
-                     if (!w9968cf_need_decompression(pict.palette)) {
-                        DBG(4, "Decompression forced: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, pict.palette))
-                        return -EINVAL;
-                     }
-                  }
-               }
-
-               if (pict.depth != w9968cf_valid_depth(pict.palette)) {
-                       DBG(4, "Requested depth %u bpp is not valid for %s "
-                              "palette: ignored and changed to %u bpp", 
-                           pict.depth, symbolic(v4l1_plist, pict.palette),
-                           w9968cf_valid_depth(pict.palette))
-                       pict.depth = w9968cf_valid_depth(pict.palette);
-               }
-
-               if (pict.palette != cam->picture.palette) {
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_picture(cam, pict))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-
-               } else if (w9968cf_sensor_update_picture(cam, pict))
-                       return -EIO;
-
-
-               DBG(5, "VIDIOCSPICT successfully called")
-               return 0;
-       }
-
-       case VIDIOCSWIN: /* set capture area */
-       {
-               struct video_window win;
-               int err = 0;
-
-               if (copy_from_user(&win, arg, sizeof(win)))
-                       return -EFAULT;
-
-               DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
-                      "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
-                   win.x, win.y, win.width, win.height)
-
-               if (win.clipcount != 0 || win.flags != 0)
-                       return -EINVAL;
-
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
-                                                     (u16*)&win.height))) {
-                       DBG(4, "Resolution not supported (%ux%u). "
-                              "VIDIOCSWIN failed", win.width, win.height)
-                       return err;
-               }
-
-               if (win.x != cam->window.x ||
-                   win.y != cam->window.y ||
-                   win.width != cam->window.width ||
-                   win.height != cam->window.height) {
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       /* This _must_ be called before set_window() */
-                       if (w9968cf_set_picture(cam, cam->picture))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_window(cam, win))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-               }
-
-               DBG(5, "VIDIOCSWIN successfully called. ")
-               return 0;
-       }
-
-       case VIDIOCGWIN: /* get current window properties */
-       {
-               if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGWIN successfully called")
-               return 0;
-       }
-
-       case VIDIOCGMBUF: /* request for memory (mapped) buffer */
-       {
-               struct video_mbuf mbuf;
-               u8 i;
-
-               mbuf.size = cam->nbuffers * cam->frame[0].size;
-               mbuf.frames = cam->nbuffers;
-               for (i = 0; i < cam->nbuffers; i++)
-                       mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
-                                         (unsigned long)cam->frame[0].buffer;
-
-               if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGMBUF successfully called")
-               return 0;
-       }
-
-       case VIDIOCMCAPTURE: /* start the capture to a frame */
-       {
-               struct video_mmap mmap;
-               struct w9968cf_frame_t* fr;
-               int err = 0;
-
-               if (copy_from_user(&mmap, arg, sizeof(mmap)))
-                       return -EFAULT;
-
-               DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
-                   mmap.frame, symbolic(v4l1_plist, mmap.format), 
-                   mmap.width, mmap.height)
-
-               if (mmap.frame >= cam->nbuffers) {
-                       DBG(4, "Invalid frame number (%u). "
-                              "VIDIOCMCAPTURE failed", mmap.frame)
-                       return -EINVAL;
-               }
-
-               if (mmap.format!=cam->picture.palette && 
-                   (cam->force_palette || !w9968cf_vpp)) {
-                       DBG(4, "Palette %s rejected: only %s is allowed",
-                           symbolic(v4l1_plist, mmap.format),
-                           symbolic(v4l1_plist, cam->picture.palette))
-                       return -EINVAL;
-               }
-
-               if (!w9968cf_valid_palette(mmap.format)) {
-                       DBG(4, "Palette %s not supported. "
-                              "VIDIOCMCAPTURE failed", 
-                           symbolic(v4l1_plist, mmap.format))
-                       return -EINVAL;
-               }
-
-               if (!cam->force_palette) {
-                  if (cam->decompression == 0) {
-                     if (w9968cf_need_decompression(mmap.format)) {
-                        DBG(4, "Decompression disabled: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, mmap.format))
-                        return -EINVAL;
-                     }
-                  } else if (cam->decompression == 1) {
-                     if (!w9968cf_need_decompression(mmap.format)) {
-                        DBG(4, "Decompression forced: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, mmap.format))
-                        return -EINVAL;
-                     }
-                  }
-               }
-
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
-                                                     (u16*)&mmap.height))) {
-                       DBG(4, "Resolution not supported (%dx%d). "
-                              "VIDIOCMCAPTURE failed",
-                           mmap.width, mmap.height)
-                       return err;
-               }
-
-               fr = &cam->frame[mmap.frame];
-
-               if (mmap.width  != cam->window.width ||
-                   mmap.height != cam->window.height ||
-                   mmap.format != cam->picture.palette) {
-
-                       struct video_window win;
-                       struct video_picture pict;
-
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               DBG(6, "VIDIOCMCAPTURE. Change settings for "
-                                      "frame #%u: %dx%d, format %s. Wait...",
-                                   mmap.frame, mmap.width, mmap.height,
-                                   symbolic(v4l1_plist, mmap.format))
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       memcpy(&win, &cam->window, sizeof(win));
-                       memcpy(&pict, &cam->picture, sizeof(pict));
-                       win.width = mmap.width;
-                       win.height = mmap.height;
-                       pict.palette = mmap.format;
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       /* This before set_window */
-                       if (w9968cf_set_picture(cam, pict)) 
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_window(cam, win))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-
-               } else  if (fr->queued) {
-
-                       DBG(6, "Wait until frame #%u is free", mmap.frame)
-                       
-                       err = wait_event_interruptible(cam->wait_queue, 
-                                                      cam->disconnected ||
-                                                      (!fr->queued));
-                       if (err)
-                               return err;
-                       if (cam->disconnected)
-                               return -ENODEV;
-               }
-
-               w9968cf_push_frame(cam, mmap.frame);
-               DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
-               return 0;
-       }
-
-       case VIDIOCSYNC: /* wait until the capture of a frame is finished */
-       {
-               unsigned int f_num;
-               struct w9968cf_frame_t* fr;
-               int err = 0;
-
-               if (copy_from_user(&f_num, arg, sizeof(f_num)))
-                       return -EFAULT;
-
-               if (f_num >= cam->nbuffers) {
-                       DBG(4, "Invalid frame number (%u). "
-                              "VIDIOCMCAPTURE failed", f_num)
-                       return -EINVAL;
-               }
-
-               DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
-
-               fr = &cam->frame[f_num];
-
-               switch (fr->status) {
-               case F_UNUSED:
-                       if (!fr->queued) {
-                               DBG(4, "VIDIOSYNC: Frame #%u not requested!",
-                                   f_num)
-                               return -EFAULT;
-                       }
-               case F_ERROR:
-               case F_GRABBING:
-                       err = wait_event_interruptible(cam->wait_queue, 
-                                                      (fr->status == F_READY)
-                                                      || cam->disconnected);
-                       if (err)
-                               return err;
-                       if (cam->disconnected)
-                               return -ENODEV;
-                       break;
-               case F_READY:
-                       break;
-               }
-
-               if (w9968cf_vpp)
-                       w9968cf_postprocess_frame(cam, fr);
-
-               fr->status = F_UNUSED;
-
-               DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
-               return 0;
-       }
-
-       case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
-       {
-               struct video_unit unit = {
-                       .video = cam->v4ldev->minor,
-                       .vbi = VIDEO_NO_UNIT,
-                       .radio = VIDEO_NO_UNIT,
-                       .audio = VIDEO_NO_UNIT,
-                       .teletext = VIDEO_NO_UNIT,
-               };
-
-               if (copy_to_user(arg, &unit, sizeof(unit)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGUNIT successfully called")
-               return 0;
-       }
-
-       case VIDIOCKEY:
-               return 0;
-
-       case VIDIOCGFBUF:
-       {
-               if (clear_user(arg, sizeof(struct video_buffer)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGFBUF successfully called")
-               return 0;
-       }
-
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner tuner;
-               if (copy_from_user(&tuner, arg, sizeof(tuner)))
-                       return -EFAULT;
-
-               if (tuner.tuner != 0)
-                       return -EINVAL;
-
-               strcpy(tuner.name, "no_tuner");
-               tuner.rangelow = 0;
-               tuner.rangehigh = 0;
-               tuner.flags = VIDEO_TUNER_NORM;
-               tuner.mode = VIDEO_MODE_AUTO;
-               tuner.signal = 0xffff;
-
-               if (copy_to_user(arg, &tuner, sizeof(tuner)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGTUNER successfully called")
-               return 0;
-       }
-
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner tuner;
-               if (copy_from_user(&tuner, arg, sizeof(tuner)))
-                       return -EFAULT;
-
-               if (tuner.tuner != 0)
-                       return -EINVAL;
-
-               if (tuner.mode != VIDEO_MODE_AUTO)
-                       return -EINVAL;
-
-               DBG(5, "VIDIOCSTUNER successfully called")
-               return 0;
-       }
-
-       case VIDIOCSFBUF:
-       case VIDIOCCAPTURE:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-       case VIDIOCSPLAYMODE:
-       case VIDIOCSWRITEMODE:
-       case VIDIOCGPLAYINFO:
-       case VIDIOCSMICROCODE:
-       case VIDIOCGVBIFMT:
-       case VIDIOCSVBIFMT:
-               DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
-                      "(type 0x%01X, "
-                      "n. 0x%01X, "
-                      "dir. 0x%01X, " 
-                      "size 0x%02X)",
-                   V4L1_IOCTL(cmd),
-                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-               return -EINVAL;
-
-       default:
-               DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
-                      "type 0x%01X, "
-                      "n. 0x%01X, "
-                      "dir. 0x%01X, "
-                      "size 0x%02X",
-                   V4L1_IOCTL(cmd),
-                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-               return -ENOIOCTLCMD;
-
-       } /* end of switch */
-
-ioctl_fail:
-       cam->misconfigured = 1;
-       DBG(1, "VIDIOC%s failed because of hardware problems. "
-              "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
-       return -EFAULT;
-}
-
-
-static struct file_operations w9968cf_fops = {
-       .owner =   THIS_MODULE,
-       .open =    w9968cf_open,
-       .release = w9968cf_release,
-       .read =    w9968cf_read,
-       .ioctl =   w9968cf_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .mmap =    w9968cf_mmap,
-       .llseek =  no_llseek,
-};
-
-
-
-/****************************************************************************
- * USB probe and V4L registration, disconnect and id_table[] definition     *
- ****************************************************************************/
-
-static int
-w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct w9968cf_device* cam;
-       int err = 0;
-       enum w9968cf_model_id mod_id;
-       struct list_head* ptr;
-       u8 sc = 0; /* number of simultaneous cameras */
-       static unsigned short dev_nr = 0; /* we are handling device number n */
-
-       if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
-           le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
-               mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
-       else if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[1].idVendor &&
-                le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
-               mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
-       else
-               return -ENODEV;
-
-       cam = (struct w9968cf_device*)
-                 kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
-       if (!cam)
-               return -ENOMEM;
-
-       mutex_init(&cam->dev_mutex);
-       mutex_lock(&cam->dev_mutex);
-
-       cam->usbdev = udev;
-       /* NOTE: a local copy is used to avoid possible race conditions */
-       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
-
-       DBG(2, "%s detected", symbolic(camlist, mod_id))
-
-       if (simcams > W9968CF_MAX_DEVICES)
-               simcams = W9968CF_SIMCAMS;
-
-       /* How many cameras are connected ? */
-       mutex_lock(&w9968cf_devlist_mutex);
-       list_for_each(ptr, &w9968cf_dev_list)
-               sc++;
-       mutex_unlock(&w9968cf_devlist_mutex);
-
-       if (sc >= simcams) {
-               DBG(2, "Device rejected: too many connected cameras "
-                      "(max. %u)", simcams)
-               err = -EPERM;
-               goto fail;
-       }
-
-
-       /* Allocate 2 bytes of memory for camera control USB transfers */
-       if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
-               DBG(1,"Couldn't allocate memory for camera control transfers")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Allocate 8 bytes of memory for USB data transfers to the FSB */
-       if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "Couldn't allocate memory for data "
-                      "transfers to the FSB")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Register the V4L device */
-       cam->v4ldev = video_device_alloc();
-       if (!cam->v4ldev) {
-               DBG(1, "Could not allocate memory for a V4L structure")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
-       cam->v4ldev->fops = &w9968cf_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-       cam->v4ldev->dev = &cam->dev;
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L device registration failed")
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(2, "Couldn't find a free /dev/videoX node")
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               goto fail;
-       }
-
-       DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
-
-       /* Set some basic constants */
-       w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
-
-       /* Add a new entry into the list of V4L registered devices */
-       mutex_lock(&w9968cf_devlist_mutex);
-       list_add(&cam->v4llist, &w9968cf_dev_list);
-       mutex_unlock(&w9968cf_devlist_mutex);
-       dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-       w9968cf_turn_on_led(cam);
-
-       w9968cf_i2c_init(cam);
-
-       usb_set_intfdata(intf, cam);
-       mutex_unlock(&cam->dev_mutex);
-       return 0;
-
-fail: /* Free unused memory */
-       kfree(cam->control_buffer);
-       kfree(cam->data_buffer);
-       if (cam->v4ldev)
-               video_device_release(cam->v4ldev);
-       mutex_unlock(&cam->dev_mutex);
-       kfree(cam);
-       return err;
-}
-
-
-static void w9968cf_usb_disconnect(struct usb_interface* intf)
-{
-       struct w9968cf_device* cam = 
-          (struct w9968cf_device*)usb_get_intfdata(intf);
-
-       down_write(&w9968cf_disconnect);
-
-       if (cam) {
-               /* Prevent concurrent accesses to data */
-               mutex_lock(&cam->dev_mutex);
-
-               cam->disconnected = 1;
-
-               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
-
-               wake_up_interruptible_all(&cam->open);
-
-               if (cam->users) {
-                       DBG(2, "The device is open (/dev/video%d)! "
-                              "Process name: %s. Deregistration and memory "
-                              "deallocation are deferred on close.",
-                           cam->v4ldev->minor, cam->command)
-                       cam->misconfigured = 1;
-                       w9968cf_stop_transfer(cam);
-                       wake_up_interruptible(&cam->wait_queue);
-               } else
-                       w9968cf_release_resources(cam);
-
-               mutex_unlock(&cam->dev_mutex);
-
-               if (!cam->users)
-                       kfree(cam);
-       }
-
-       up_write(&w9968cf_disconnect);
-}
-
-
-static struct usb_driver w9968cf_usb_driver = {
-       .name =       "w9968cf",
-       .id_table =   winbond_id_table,
-       .probe =      w9968cf_usb_probe,
-       .disconnect = w9968cf_usb_disconnect,
-};
-
-
-
-/****************************************************************************
- * Module init, exit and intermodule communication                          *
- ****************************************************************************/
-
-static int __init w9968cf_module_init(void)
-{
-       int err;
-
-       KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
-       KDBG(3, W9968CF_MODULE_AUTHOR)
-
-       if (ovmod_load)
-               request_module("ovcamchip");
-
-       if ((err = usb_register(&w9968cf_usb_driver)))
-               return err;
-
-       return 0;
-}
-
-
-static void __exit w9968cf_module_exit(void)
-{
-       /* w9968cf_usb_disconnect() will be called */
-       usb_deregister(&w9968cf_usb_driver);
-
-       KDBG(2, W9968CF_MODULE_NAME" deregistered")
-}
-
-
-module_init(w9968cf_module_init);
-module_exit(w9968cf_module_exit);
-
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h
deleted file mode 100644 (file)
index a87be71..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_H_
-#define _W9968CF_H_
-
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/config.h>
-#include <linux/param.h>
-#include <linux/types.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-
-#include <media/ovcamchip.h>
-
-#include "w9968cf_vpp.h"
-
-
-/****************************************************************************
- * Default values                                                           *
- ****************************************************************************/
-
-#define W9968CF_OVMOD_LOAD      1  /* automatic 'ovcamchip' module loading */
-#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
-
-/* Comment/uncomment the following line to enable/disable debugging messages */
-#define W9968CF_DEBUG
-
-/* These have effect only if W9968CF_DEBUG is defined */
-#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
-#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
-
-#define W9968CF_MAX_DEVICES    32
-#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
-
-#define W9968CF_MAX_BUFFERS   32
-#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
-
-/* Maximum data payload sizes in bytes for alternate settings */
-static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
-                                      511, 447, 383, 319, 255, 191, 127,  63};
-#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
-#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
-#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
-#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
-
-#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
-#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
-
-/* Available video formats */
-struct w9968cf_format {
-       const u16 palette;
-       const u16 depth;
-       const u8 compression;
-};
-
-static const struct w9968cf_format w9968cf_formatlist[] = {
-       { VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
-       { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
-       { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
-       { VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
-       { VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
-       { 0,                      0, 0 }  /* 0 is a terminating entry */
-};
-
-#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
-#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
-#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
-#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
-
-#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
-
-#define W9968CF_MAX_WIDTH      800 /* Has effect if up-scaling is on */
-#define W9968CF_MAX_HEIGHT     600 /* Has effect if up-scaling is on */
-#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
-#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
-
-#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
-#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
-#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
-#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
-#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
-
-#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
-#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
-#define W9968CF_HUE            32768 /* from 0 to 65535 */
-#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
-#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
-#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
-
-#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
-#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
-#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
-#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
-#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
-#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
-
-#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
-#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
-
-
-/****************************************************************************
- * Globals                                                                  *
- ****************************************************************************/
-
-#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
-                                "Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION  "1:1.33-basic"
-#define W9968CF_MODULE_AUTHOR   "(C) 2002-2004 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define W9968CF_MODULE_LICENSE  "GPL"
-
-static const struct usb_device_id winbond_id_table[] = {
-       {
-               /* Creative Labs Video Blaster WebCam Go Plus */
-               USB_DEVICE(0x041e, 0x4003),
-               .driver_info = (unsigned long)"w9968cf",
-       },
-       {
-               /* Generic W996[87]CF JPEG USB Dual Mode Camera */
-               USB_DEVICE(0x1046, 0x9967),
-               .driver_info = (unsigned long)"w9968cf",
-       },
-       { } /* terminating entry */
-};
-
-/* W996[87]CF camera models, internal ids: */
-enum w9968cf_model_id {
-       W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
-       W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
-       W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
-       W9986CF_MOD_AAU = 31,     /* AVerMedia AVerTV USB */
-       W9968CF_MOD_CLVBWG = 34,  /* Creative Labs Video Blaster WebCam Go */
-       W9968CF_MOD_LL = 37,      /* Lebon LDC-035A */
-       W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
-       W9968CF_MOD_OOE = 42,     /* OmniVision OV8610-EDE */
-       W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
-       W9968CF_MOD_PDPII = 46,   /* Pretec Digi Pen-II */
-       W9968CF_MOD_PDP480 = 49,  /* Pretec DigiPen-480 */
-};
-
-enum w9968cf_frame_status {
-       F_READY,            /* finished grabbing & ready to be read/synced */
-       F_GRABBING,         /* in the process of being grabbed into */
-       F_ERROR,            /* something bad happened while processing */
-       F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
-};
-
-struct w9968cf_frame_t {
-       void* buffer;
-       unsigned long size;
-       u32 length;
-       int number;
-       enum w9968cf_frame_status status;
-       struct w9968cf_frame_t* next;
-       u8 queued;
-};
-
-enum w9968cf_vpp_flag {
-       VPP_NONE = 0x00,
-       VPP_UPSCALE = 0x01,
-       VPP_SWAP_YUV_BYTES = 0x02,
-       VPP_DECOMPRESSION = 0x04,
-       VPP_UYVY_TO_RGBX = 0x08,
-};
-
-/* Main device driver structure */
-struct w9968cf_device {
-       struct device dev; /* device structure */
-
-       enum w9968cf_model_id id;   /* private device identifier */
-
-       struct video_device* v4ldev; /* -> V4L structure */
-       struct list_head v4llist;    /* entry of the list of V4L cameras */
-
-       struct usb_device* usbdev;           /* -> main USB structure */
-       struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
-       void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
-       u16* control_buffer;                 /* -> buffer for control req.*/
-       u16* data_buffer;                    /* -> data to send to the FSB */
-
-       struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
-       struct w9968cf_frame_t frame_tmp; /* temporary frame */
-       struct w9968cf_frame_t frame_vpp; /* helper frame.*/
-       struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
-       struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-
-       u8 max_buffers,   /* number of requested buffers */
-          force_palette, /* yes=1/no=0 */
-          force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
-          double_buffer, /* hardware double buffering yes=1/no=0 */
-          clamping,      /* video data clamping yes=1/no=0 */
-          filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
-          capture,       /* 0=disabled, 1=enabled */
-          largeview,     /* 0=disabled, 1=enabled */
-          decompression, /* 0=disabled, 1=forced, 2=allowed */
-          upscaling;     /* software image scaling, 0=enabled, 1=disabled */
-
-       struct video_picture picture; /* current picture settings */
-       struct video_window window;   /* current window settings */
-
-       u16 hw_depth,    /* depth (used by the chip) */
-           hw_palette,  /* palette (used by the chip) */
-           hw_width,    /* width (used by the chip) */
-           hw_height,   /* height (used by the chip) */
-           hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-           vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-           start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
-           start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
-
-       enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
-
-       u8 nbuffers,      /* number of allocated frame buffers */
-          altsetting,    /* camera alternate setting */
-          disconnected,  /* flag: yes=1, no=0 */
-          misconfigured, /* flag: yes=1, no=0 */
-          users,         /* flag: number of users holding the device */
-          streaming;     /* flag: yes=1, no=0 */
-
-       u8 sensor_initialized; /* flag: yes=1, no=0 */
-
-       /* Determined by the image sensor type: */
-       int sensor,       /* type of image sensor chip (CC_*) */
-           monochrome;   /* image sensor is (probably) monochrome */
-       u16 maxwidth,     /* maximum width supported by the image sensor */
-           maxheight,    /* maximum height supported by the image sensor */
-           minwidth,     /* minimum width supported by the image sensor */
-           minheight;    /* minimum height supported by the image sensor */
-       u8  auto_brt,     /* auto brightness enabled flag */
-           auto_exp,     /* auto exposure enabled flag */
-           backlight,    /* backlight exposure algorithm flag */
-           mirror,       /* image is reversed horizontally */
-           lightfreq,    /* power (lighting) frequency */
-           bandfilt;     /* banding filter enabled flag */
-       s8  clockdiv;     /* clock divisor */
-
-       /* I2C interface to kernel */
-       struct i2c_adapter i2c_adapter;
-       struct i2c_client* sensor_client;
-
-       /* Locks */
-       struct mutex dev_mutex,    /* for probe, disconnect,open and close */
-                        fileop_mutex; /* for read and ioctl */
-       spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
-                  flist_lock; /* for requested frame list accesses */
-       wait_queue_head_t open, wait_queue;
-
-       char command[16]; /* name of the program holding the device */
-};
-
-
-/****************************************************************************
- * Macros for debugging                                                     *
- ****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef W9968CF_DEBUG
-/* For device specific debugging messages */
-#      define DBG(level, fmt, args...)                                       \
-{                                                                             \
-       if ( ((specific_debug) && (debug == (level))) ||                      \
-            ((!specific_debug) && (debug >= (level))) ) {                    \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->dev, fmt "\n", ## args);                \
-               else if ((level) == 2 || (level) == 3)                        \
-                       dev_info(&cam->dev, fmt "\n", ## args);               \
-               else if ((level) == 4)                                        \
-                       dev_warn(&cam->dev, fmt "\n", ## args);               \
-               else if ((level) >= 5)                                        \
-                       dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-}
-/* For generic kernel (not device specific) messages */
-#      define KDBG(level, fmt, args...)                                      \
-{                                                                             \
-       if ( ((specific_debug) && (debug == (level))) ||                      \
-            ((!specific_debug) && (debug >= (level))) ) {                    \
-               if ((level) >= 1 && (level) <= 4)                             \
-                       pr_info("w9968cf: " fmt "\n", ## args);               \
-               else if ((level) >= 5)                                        \
-                       pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__,  \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-}
-#else
-       /* Not debugging: nothing */
-#      define DBG(level, fmt, args...) do {;} while(0);
-#      define KDBG(level, fmt, args...) do {;} while(0);
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
-
-#endif /* _W9968CF_H_ */
diff --git a/drivers/usb/media/w9968cf_decoder.h b/drivers/usb/media/w9968cf_decoder.h
deleted file mode 100644 (file)
index 31faccb..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Video decoder for the W996[87]CF driver for Linux.                      *
- *                                                                         *
- * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_DECODER_H_
-#define _W9968CF_DECODER_H_
-
-/* Comment/uncomment this for high/low quality of compressed video */
-#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-
-#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-static const unsigned char Y_QUANTABLE[64] = {
-       16,  11,  10,  16,  24,  40,  51,  61,
-       12,  12,  14,  19,  26,  58,  60,  55,
-       14,  13,  16,  24,  40,  57,  69,  56,
-       14,  17,  22,  29,  51,  87,  80,  62,
-       18,  22,  37,  56,  68, 109, 103,  77,
-       24,  35,  55,  64,  81, 104, 113,  92,
-       49,  64,  78,  87, 103, 121, 120, 101,
-       72,  92,  95,  98, 112, 100, 103,  99
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-       17,  18,  24,  47,  99,  99,  99,  99,
-       18,  21,  26,  66,  99,  99,  99,  99,
-       24,  26,  56,  99,  99,  99,  99,  99,
-       47,  66,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99
-};
-#else
-static const unsigned char Y_QUANTABLE[64] = {
-        8,   5,   5,   8,  12,  20,  25,  30,
-        6,   6,   7,   9,  13,  29,  30,  27,
-        7,   6,   8,  12,  20,  28,  34,  28,
-        7,   8,  11,  14,  25,  43,  40,  31,
-        9,  11,  18,  28,  34,  54,  51,  38,
-       12,  17,  27,  32,  40,  52,  56,  46,
-       24,  32,  39,  43,  51,  60,  60,  50,
-       36,  46,  47,  49,  56,  50,  51,  49
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-        8,   9,  12,  23,  49,  49,  49,  49,
-        9,  10,  13,  33,  49,  49,  49,  49,
-       12,  13,  28,  49,  49,  49,  49,  49,
-       23,  33,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49
-};
-#endif
-
-#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
-#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
-#define W9968CF_DEC_ERR_NO_SOI          -3
-#define W9968CF_DEC_ERR_NO_SOF0         -4
-#define W9968CF_DEC_ERR_NO_SOS          -5
-#define W9968CF_DEC_ERR_NO_EOI          -6
-
-extern void w9968cf_init_decoder(void);
-extern int w9968cf_check_headers(const unsigned char* Pin, 
-                                 const unsigned long BUF_SIZE);
-extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, 
-                          const unsigned W, const unsigned H, char* Pout);
-
-#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/usb/media/w9968cf_vpp.h b/drivers/usb/media/w9968cf_vpp.h
deleted file mode 100644 (file)
index f3b91b7..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- * Interface for video post-processing functions for the W996[87]CF driver *
- * for Linux.                                                              *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_VPP_H_
-#define _W9968CF_VPP_H_
-
-#include <linux/module.h>
-#include <asm/types.h>
-
-struct w9968cf_vpp_t {
-       struct module* owner;
-       int (*check_headers)(const unsigned char*, const unsigned long);
-       int (*decode)(const char*, const unsigned long, const unsigned,
-                     const unsigned, char*);
-       void (*swap_yuvbytes)(void*, unsigned long);
-       void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
-       void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
-
-       u8 busy; /* read-only flag: module is/is not in use */
-};
-
-#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h
deleted file mode 100644 (file)
index 8e06551..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ZC0301_H_
-#define _ZC0301_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-
-#include "zc0301_sensor.h"
-
-/*****************************************************************************/
-
-#define ZC0301_DEBUG
-#define ZC0301_DEBUG_LEVEL         2
-#define ZC0301_MAX_DEVICES         64
-#define ZC0301_FORCE_MUNMAP        0
-#define ZC0301_MAX_FRAMES          32
-#define ZC0301_COMPRESSION_QUALITY 0
-#define ZC0301_URBS                2
-#define ZC0301_ISO_PACKETS         7
-#define ZC0301_ALTERNATE_SETTING   7
-#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
-#define ZC0301_CTRL_TIMEOUT        100
-#define ZC0301_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-ZC0301_ID_TABLE
-ZC0301_SENSOR_TABLE
-
-enum zc0301_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct zc0301_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum zc0301_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum zc0301_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum zc0301_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum zc0301_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-struct zc0301_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DECLARE_RWSEM(zc0301_disconnect);
-
-struct zc0301_device {
-       struct video_device* v4ldev;
-
-       struct zc0301_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[ZC0301_URBS];
-       void* transfer_buffer[ZC0301_URBS];
-       u8* control_buffer;
-
-       struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum zc0301_io_method io;
-       enum zc0301_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct zc0301_module_param module_param;
-
-       enum zc0301_dev_state state;
-       u8 users;
-
-       struct mutex dev_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
-{
-       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ZC0301_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("zc0301: " fmt "\n", ## args);                \
-               else if ((level) == 3)                                        \
-                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-         __FUNCTION__, __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ZC0301_H_ */
diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c
deleted file mode 100644 (file)
index 4036c62..0000000
+++ /dev/null
@@ -1,2055 +0,0 @@
-/***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * Informations about the chip internals needed to enable the I2C protocol *
- * have been taken from the documentation of the ZC030x Video4Linux1       *
- * driver written by Andrew Birkett <andy@nobugs.org>                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "zc0301.h"
-
-/*****************************************************************************/
-
-#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
-                              "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
-#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.03"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, zc0301_id_table);
-
-MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
-MODULE_VERSION(ZC0301_MODULE_VERSION);
-MODULE_LICENSE(ZC0301_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "
-                 __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second registered camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-                               ZC0301_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-                                       ZC0301_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                 "\n<n[,...]> Timeout for a video frame in seconds."
-                 "\nThis parameter is specific for each detected camera."
-                 "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
-                 "\n");
-
-#ifdef ZC0301_DEBUG
-static unsigned short debug = ZC0301_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
-                 "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-zc0301_request_buffers(struct zc0301_device* cam, u32 count,
-                       enum zc0301_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > ZC0301_MAX_FRAMES)
-               count = ZC0301_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void zc0301_release_buffers(struct zc0301_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void zc0301_empty_framequeues(struct zc0301_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void zc0301_requeue_outqueue(struct zc0301_device* cam)
-{
-       struct zc0301_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void zc0301_queue_unusedframes(struct zc0301_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
-{
-       struct usb_device* udev = cam->usbdev;
-       int res;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
-                             value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (index 0x%04X, "
-                      "value 0x%02X, error %d)",index, value, res);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-int zc0301_read_reg(struct zc0301_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
-                             0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%04X, error %d)",
-                   index, res);
-
-       PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
-{
-       int err = 0, res, r0, r1;
-
-       err += zc0301_write_reg(cam, 0x0092, address);
-       err += zc0301_write_reg(cam, 0x0090, 0x02);
-
-       msleep(1);
-
-       res = zc0301_read_reg(cam, 0x0091);
-       if (res < 0)
-               err += res;
-       r0 = zc0301_read_reg(cam, 0x0095);
-       if (r0 < 0)
-               err += r0;
-       r1 = zc0301_read_reg(cam, 0x0096);
-       if (r1 < 0)
-               err += r1;
-
-       res = (length <= 1) ? r0 : r0 | (r1 << 8);
-
-       if (err)
-               DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
-                   address, res);
-
-
-       PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
-
-       return err ? -1 : res;
-}
-
-
-int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
-{
-       int err = 0, res;
-
-       err += zc0301_write_reg(cam, 0x0092, address);
-       err += zc0301_write_reg(cam, 0x0093, value & 0xff);
-       err += zc0301_write_reg(cam, 0x0094, value >> 8);
-       err += zc0301_write_reg(cam, 0x0090, 0x01);
-
-       msleep(1);
-
-       res = zc0301_read_reg(cam, 0x0091);
-       if (res < 0)
-               err += res;
-
-       if (err)
-               DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
-                   address, value);
-
-       PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
-
-       return err ? -1 : 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
-{
-       struct zc0301_device* cam = urb->context;
-       struct zc0301_frame_t** f;
-       size_t imagesize;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int len, status;
-               void *pos;
-               u16* soi;
-               u8 sof;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               sof = (*(soi = pos) == 0xd8ff);
-
-               PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
-
-               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-                       if (sof) {
-                               (*f)->state = F_GRABBING;
-                               (*f)->buf.bytesused = 0;
-                               do_gettimeofday(&(*f)->buf.timestamp);
-                               DBG(3, "SOF detected: new video frame");
-                       }
-
-               if ((*f)->state == F_GRABBING) {
-                       if (sof && (*f)->buf.bytesused)
-                                       goto end_of_frame;
-
-                       if ((*f)->buf.bytesused + len > imagesize) {
-                               DBG(3, "Video frame size exceeded");
-                               (*f)->state = F_ERROR;
-                               continue;
-                       }
-
-                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
-                       (*f)->buf.bytesused += len;
-
-                       if ((*f)->buf.bytesused == imagesize) {
-                               u32 b;
-end_of_frame:
-                               b = (*f)->buf.bytesused;
-                               (*f)->state = F_DONE;
-                               (*f)->buf.sequence= ++cam->frame_count;
-                               spin_lock(&cam->queue_lock);
-                               list_move_tail(&(*f)->frame, &cam->outqueue);
-                               if (!list_empty(&cam->inqueue))
-                                       (*f) = list_entry(cam->inqueue.next,
-                                                      struct zc0301_frame_t,
-                                                         frame);
-                               else
-                                       (*f) = NULL;
-                               spin_unlock(&cam->queue_lock);
-                               DBG(3, "Video frame captured: : %lu bytes",
-                                      (unsigned long)(b));
-
-                               if (!(*f))
-                                       goto resubmit_urb;
-
-                               if (sof)
-                                       goto start_of_frame;
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int zc0301_start_transfer(struct zc0301_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
-                                              512, 768, 1023};
-       const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = ZC0301_ISO_PACKETS;
-               urb->complete = zc0301_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < ZC0301_URBS) &&  cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int zc0301_stop_transfer(struct zc0301_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = ZC0301_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int zc0301_stream_interrupt(struct zc0301_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    ZC0301_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. To "
-                      "use it, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_set_compression(struct zc0301_device* cam,
-                       struct v4l2_jpegcompression* compression)
-{
-       int r, err = 0;
-
-       if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
-               err += r;
-       err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
-
-       return err ? -EIO : 0;
-}
-
-
-static int zc0301_init(struct zc0301_device* cam)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-               cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       if ((err = zc0301_set_compression(cam, &cam->compression))) {
-               DBG(3, "set_compression() failed");
-               return err;
-       }
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-
-static void zc0301_release_resources(struct zc0301_device* cam)
-{
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-       kfree(cam->control_buffer);
-}
-
-/*****************************************************************************/
-
-static int zc0301_open(struct inode* inode, struct file* filp)
-{
-       struct zc0301_device* cam;
-       int err = 0;
-
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&zc0301_disconnect))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&zc0301_disconnect);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
-               if (err) {
-                       up_read(&zc0301_disconnect);
-                       return err;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&zc0301_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = zc0301_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = zc0301_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       zc0301_empty_framequeues(cam);
-
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
-
-out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&zc0301_disconnect);
-       return err;
-}
-
-
-static int zc0301_release(struct inode* inode, struct file* filp)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       zc0301_stop_transfer(cam);
-
-       zc0301_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               zc0301_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-}
-
-
-static ssize_t
-zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       struct zc0301_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose the read "
-                      "method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       zc0301_empty_framequeues(cam);
-               zc0301_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       zc0301_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err ? err : count;
-}
-
-
-static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       struct zc0301_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               zc0301_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void zc0301_vm_open(struct vm_area_struct* vma)
-{
-       struct zc0301_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void zc0301_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct zc0301_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static struct vm_operations_struct zc0301_vm_ops = {
-       .open = zc0301_vm_open,
-       .close = zc0301_vm_close,
-};
-
-
-static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &zc0301_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-
-       zc0301_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "zc0301",
-               .version = ZC0301_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       const enum zc0301_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (!s->set_crop) {
-               memcpy(rect, &(s->_rect), sizeof(*rect));
-               if (copy_to_user(arg, &crop, sizeof(crop)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       rect->left &= ~7L;
-       rect->top &= ~7L;
-       if (rect->width < 8)
-               rect->width = 8;
-       if (rect->height < 8)
-               rect->height = 8;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-       rect->width &= ~7L;
-       rect->height &= ~7L;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               zc0301_release_buffers(cam);
-
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width;
-       s->pix_format.height = rect->height;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               zc0301_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               zc0301_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "JPEG");
-               fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = 0;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
-                        void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       const enum zc0301_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       if (!s->set_crop) {
-               pix->width = rect.width;
-               pix->height = rect.height;
-       } else {
-               rect.width = pix->width;
-               rect.height = pix->height;
-       }
-
-       if (rect.width < 8)
-               rect.width = 8;
-       if (rect.height < 8)
-               rect.height = 8;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-       rect.width &= ~7L;
-       rect.height &= ~7L;
-
-       pix->width = rect.width;
-       pix->height = rect.height;
-       pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv;
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = 0;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               zc0301_release_buffers(cam);
-
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               zc0301_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               zc0301_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum zc0301_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       err += zc0301_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open "
-                      "/dev/video%d again.", cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. "
-                              "Previous buffers are still mapped.");
-                       return -EINVAL;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       zc0301_empty_framequeues(cam);
-
-       zc0301_release_buffers(cam);
-       if (rb.count)
-               rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               zc0301_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
-                    void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct zc0301_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       zc0301_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
-               sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
-                             unsigned int cmd, void __user * arg)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return zc0301_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return zc0301_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return zc0301_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return zc0301_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return zc0301_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return zc0301_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-               return zc0301_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP_OLD:
-       case VIDIOC_CROPCAP:
-               return zc0301_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return zc0301_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return zc0301_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return zc0301_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return zc0301_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return zc0301_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return zc0301_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return zc0301_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return zc0301_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return zc0301_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return zc0301_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return zc0301_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return zc0301_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return zc0301_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-               return zc0301_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static int zc0301_ioctl(struct inode* inode, struct file* filp,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "zc0301", cmd);
-
-       err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-
-static struct file_operations zc0301_fops = {
-       .owner =   THIS_MODULE,
-       .open =    zc0301_open,
-       .release = zc0301_release,
-       .ioctl =   zc0301_ioctl,
-       .read =    zc0301_read,
-       .poll =    zc0301_poll,
-       .mmap =    zc0301_mmap,
-       .llseek =  no_llseek,
-};
-
-/*****************************************************************************/
-
-static int
-zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct zc0301_device* cam;
-       static unsigned int dev_nr = 0;
-       unsigned int i;
-       int err = 0;
-
-       if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       mutex_init(&cam->dev_mutex);
-
-       DBG(2, "ZC0301 Image Processor and Control Chip detected "
-              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
-
-       for  (i = 0; zc0301_sensor_table[i]; i++) {
-               err = zc0301_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err)
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-       else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (zc0301_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
-       cam->v4ldev->fops = &zc0301_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       mutex_lock(&cam->dev_mutex);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-       usb_set_intfdata(intf, cam);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void zc0301_usb_disconnect(struct usb_interface* intf)
-{
-       struct zc0301_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
-
-       down_write(&zc0301_disconnect);
-
-       mutex_lock(&cam->dev_mutex);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       wake_up_interruptible_all(&cam->open);
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor);
-               cam->state |= DEV_MISCONFIGURED;
-               zc0301_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
-               cam->state |= DEV_DISCONNECTED;
-               zc0301_release_resources(cam);
-       }
-
-       mutex_unlock(&cam->dev_mutex);
-
-       if (!cam->users)
-               kfree(cam);
-
-       up_write(&zc0301_disconnect);
-}
-
-
-static struct usb_driver zc0301_usb_driver = {
-       .name =       "zc0301",
-       .id_table =   zc0301_id_table,
-       .probe =      zc0301_usb_probe,
-       .disconnect = zc0301_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init zc0301_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
-       KDBG(3, ZC0301_MODULE_AUTHOR);
-
-       if ((err = usb_register(&zc0301_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit zc0301_module_exit(void)
-{
-       usb_deregister(&zc0301_usb_driver);
-}
-
-
-module_init(zc0301_module_init);
-module_exit(zc0301_module_exit);
diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c
deleted file mode 100644 (file)
index 9d282a2..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
- * Processor and Control Chip                                              *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-/*
-   NOTE: Sensor controls are disabled for now, becouse changing them while
-         streaming sometimes results in out-of-sync video frames. We'll use
-         the default initialization, until we know how to stop and start video
-         in the chip. However, the image quality still looks good under various
-         light conditions.
-*/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct zc0301_device* cam)
-{
-       int err = 0;
-
-       err += zc0301_write_reg(cam, 0x0002, 0x00);
-       err += zc0301_write_reg(cam, 0x0003, 0x02);
-       err += zc0301_write_reg(cam, 0x0004, 0x80);
-       err += zc0301_write_reg(cam, 0x0005, 0x01);
-       err += zc0301_write_reg(cam, 0x0006, 0xE0);
-       err += zc0301_write_reg(cam, 0x0098, 0x00);
-       err += zc0301_write_reg(cam, 0x009A, 0x03);
-       err += zc0301_write_reg(cam, 0x011A, 0x00);
-       err += zc0301_write_reg(cam, 0x011C, 0x03);
-       err += zc0301_write_reg(cam, 0x009B, 0x01);
-       err += zc0301_write_reg(cam, 0x009C, 0xE6);
-       err += zc0301_write_reg(cam, 0x009D, 0x02);
-       err += zc0301_write_reg(cam, 0x009E, 0x86);
-
-       err += zc0301_i2c_write(cam, 0x02, 0x02);
-       err += zc0301_i2c_write(cam, 0x0A, 0x01);
-       err += zc0301_i2c_write(cam, 0x0B, 0x01);
-       err += zc0301_i2c_write(cam, 0x0D, 0x00);
-       err += zc0301_i2c_write(cam, 0x12, 0x05);
-       err += zc0301_i2c_write(cam, 0x13, 0x63);
-       err += zc0301_i2c_write(cam, 0x15, 0x70);
-
-       err += zc0301_write_reg(cam, 0x0101, 0xB7);
-       err += zc0301_write_reg(cam, 0x0100, 0x0D);
-       err += zc0301_write_reg(cam, 0x0189, 0x06);
-       err += zc0301_write_reg(cam, 0x01AD, 0x00);
-       err += zc0301_write_reg(cam, 0x01C5, 0x03);
-       err += zc0301_write_reg(cam, 0x01CB, 0x13);
-       err += zc0301_write_reg(cam, 0x0250, 0x08);
-       err += zc0301_write_reg(cam, 0x0301, 0x08);
-       err += zc0301_write_reg(cam, 0x018D, 0x70);
-       err += zc0301_write_reg(cam, 0x0008, 0x03);
-       err += zc0301_write_reg(cam, 0x01C6, 0x04);
-       err += zc0301_write_reg(cam, 0x01CB, 0x07);
-       err += zc0301_write_reg(cam, 0x0120, 0x11);
-       err += zc0301_write_reg(cam, 0x0121, 0x37);
-       err += zc0301_write_reg(cam, 0x0122, 0x58);
-       err += zc0301_write_reg(cam, 0x0123, 0x79);
-       err += zc0301_write_reg(cam, 0x0124, 0x91);
-       err += zc0301_write_reg(cam, 0x0125, 0xA6);
-       err += zc0301_write_reg(cam, 0x0126, 0xB8);
-       err += zc0301_write_reg(cam, 0x0127, 0xC7);
-       err += zc0301_write_reg(cam, 0x0128, 0xD3);
-       err += zc0301_write_reg(cam, 0x0129, 0xDE);
-       err += zc0301_write_reg(cam, 0x012A, 0xE6);
-       err += zc0301_write_reg(cam, 0x012B, 0xED);
-       err += zc0301_write_reg(cam, 0x012C, 0xF3);
-       err += zc0301_write_reg(cam, 0x012D, 0xF8);
-       err += zc0301_write_reg(cam, 0x012E, 0xFB);
-       err += zc0301_write_reg(cam, 0x012F, 0xFF);
-       err += zc0301_write_reg(cam, 0x0130, 0x26);
-       err += zc0301_write_reg(cam, 0x0131, 0x23);
-       err += zc0301_write_reg(cam, 0x0132, 0x20);
-       err += zc0301_write_reg(cam, 0x0133, 0x1C);
-       err += zc0301_write_reg(cam, 0x0134, 0x16);
-       err += zc0301_write_reg(cam, 0x0135, 0x13);
-       err += zc0301_write_reg(cam, 0x0136, 0x10);
-       err += zc0301_write_reg(cam, 0x0137, 0x0D);
-       err += zc0301_write_reg(cam, 0x0138, 0x0B);
-       err += zc0301_write_reg(cam, 0x0139, 0x09);
-       err += zc0301_write_reg(cam, 0x013A, 0x07);
-       err += zc0301_write_reg(cam, 0x013B, 0x06);
-       err += zc0301_write_reg(cam, 0x013C, 0x05);
-       err += zc0301_write_reg(cam, 0x013D, 0x04);
-       err += zc0301_write_reg(cam, 0x013E, 0x03);
-       err += zc0301_write_reg(cam, 0x013F, 0x02);
-       err += zc0301_write_reg(cam, 0x010A, 0x4C);
-       err += zc0301_write_reg(cam, 0x010B, 0xF5);
-       err += zc0301_write_reg(cam, 0x010C, 0xFF);
-       err += zc0301_write_reg(cam, 0x010D, 0xF9);
-       err += zc0301_write_reg(cam, 0x010E, 0x51);
-       err += zc0301_write_reg(cam, 0x010F, 0xF5);
-       err += zc0301_write_reg(cam, 0x0110, 0xFB);
-       err += zc0301_write_reg(cam, 0x0111, 0xED);
-       err += zc0301_write_reg(cam, 0x0112, 0x5F);
-       err += zc0301_write_reg(cam, 0x0180, 0x00);
-       err += zc0301_write_reg(cam, 0x0019, 0x00);
-       err += zc0301_write_reg(cam, 0x0087, 0x20);
-       err += zc0301_write_reg(cam, 0x0088, 0x21);
-
-       err += zc0301_i2c_write(cam, 0x20, 0x02);
-       err += zc0301_i2c_write(cam, 0x21, 0x1B);
-       err += zc0301_i2c_write(cam, 0x03, 0x44);
-       err += zc0301_i2c_write(cam, 0x0E, 0x01);
-       err += zc0301_i2c_write(cam, 0x0F, 0x00);
-
-       err += zc0301_write_reg(cam, 0x01A9, 0x14);
-       err += zc0301_write_reg(cam, 0x01AA, 0x24);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0191, 0x02);
-       err += zc0301_write_reg(cam, 0x0192, 0x1B);
-       err += zc0301_write_reg(cam, 0x0195, 0x00);
-       err += zc0301_write_reg(cam, 0x0196, 0x00);
-       err += zc0301_write_reg(cam, 0x0197, 0x4D);
-       err += zc0301_write_reg(cam, 0x018C, 0x10);
-       err += zc0301_write_reg(cam, 0x018F, 0x20);
-       err += zc0301_write_reg(cam, 0x001D, 0x44);
-       err += zc0301_write_reg(cam, 0x001E, 0x6F);
-       err += zc0301_write_reg(cam, 0x001F, 0xAD);
-       err += zc0301_write_reg(cam, 0x0020, 0xEB);
-       err += zc0301_write_reg(cam, 0x0087, 0x0F);
-       err += zc0301_write_reg(cam, 0x0088, 0x0E);
-       err += zc0301_write_reg(cam, 0x0180, 0x40);
-       err += zc0301_write_reg(cam, 0x0192, 0x1B);
-       err += zc0301_write_reg(cam, 0x0191, 0x02);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0116, 0x1D);
-       err += zc0301_write_reg(cam, 0x0117, 0x40);
-       err += zc0301_write_reg(cam, 0x0118, 0x99);
-       err += zc0301_write_reg(cam, 0x0180, 0x42);
-       err += zc0301_write_reg(cam, 0x0116, 0x1D);
-       err += zc0301_write_reg(cam, 0x0117, 0x40);
-       err += zc0301_write_reg(cam, 0x0118, 0x99);
-       err += zc0301_write_reg(cam, 0x0007, 0x00);
-
-       err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-       msleep(100);
-
-       return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct zc0301_device* cam,
-                              struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = zc0301_i2c_read(cam, 0x04, 1),
-                           r2 = zc0301_i2c_read(cam, 0x05, 1);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case ZC0301_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
-                       return -EIO;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas202bcb_set_ctrl(struct zc0301_device* cam,
-                              const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += zc0301_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += zc0301_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += zc0301_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case ZC0301_V4L2_CID_GREEN_BALANCE:
-               err += zc0301_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-               err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static struct zc0301_sensor pas202bcb = {
-       .name = "PAS202BCB",
-       .init = &pas202bcb_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-       },
-       .get_ctrl = &pas202bcb_get_ctrl,
-       .set_ctrl = &pas202bcb_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_JPEG,
-               .priv = 8,
-       },
-};
-
-
-int zc0301_probe_pas202bcb(struct zc0301_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       err += zc0301_write_reg(cam, 0x0000, 0x01);
-       err += zc0301_write_reg(cam, 0x0010, 0x0e);
-       err += zc0301_write_reg(cam, 0x0001, 0x01);
-       err += zc0301_write_reg(cam, 0x0012, 0x03);
-       err += zc0301_write_reg(cam, 0x0012, 0x01);
-       err += zc0301_write_reg(cam, 0x008d, 0x08);
-
-       msleep(10);
-
-       r0 = zc0301_i2c_read(cam, 0x00, 1);
-       r1 = zc0301_i2c_read(cam, 0x01, 1);
-
-       if (r0 < 0 || r1 < 0 || err)
-               return -EIO;
-
-       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x017)
-               return -ENODEV;
-
-       zc0301_attach_sensor(cam, &pas202bcb);
-
-       return 0;
-}
diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h
deleted file mode 100644 (file)
index cf0965a..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and       *
- * Control Chip                                                            *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ZC0301_SENSOR_H_
-#define _ZC0301_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct zc0301_device;
-struct zc0301_sensor;
-
-/*****************************************************************************/
-
-extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
-
-#define ZC0301_SENSOR_TABLE                                                   \
-/* Weak detections must go at the end of the list */                          \
-static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
-       &zc0301_probe_pas202bcb,                                              \
-       NULL,                                                                 \
-};
-
-extern struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
-
-extern void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
-
-#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-       .idVendor = (vend),                                                   \
-       .idProduct = (prod),                                                  \
-       .bInterfaceClass = (intclass)
-
-#define ZC0301_ID_TABLE                                                       \
-static const struct usb_device_id zc0301_id_table[] =  {                      \
-       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
-       { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
-       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
-       { }                                                                   \
-};
-
-/*****************************************************************************/
-
-extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
-extern int zc0301_read_reg(struct zc0301_device*, u16 index);
-extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
-extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
-
-/*****************************************************************************/
-
-#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-
-struct zc0301_sensor {
-       char name[32];
-
-       struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
-       struct v4l2_cropcap cropcap;
-       struct v4l2_pix_format pix_format;
-
-       int (*init)(struct zc0301_device*);
-       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct zc0301_device*,
-                       const struct v4l2_control* ctrl);
-       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
-
-       /* Private */
-       struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-#endif /* _ZC0301_SENSOR_H_ */
index ada6e75eb048544688e1ca099f002dba1020175a..60831bb236851d305b391647039708afd5d004e0 100644 (file)
 
 #include <asm/hardware/locomo.h>
 #include <asm/irq.h>
+#include <asm/mach/sharpsl_param.h>
+#include <asm/mach-types.h>
 
-#ifdef CONFIG_SA1100_COLLIE
-#include <asm/arch/collie.h>
-#else
-#include <asm/arch/poodle.h>
-#endif
-
-extern void (*sa1100fb_lcd_power)(int on);
+#include "../../../arch/arm/mach-sa1100/generic.h"
 
 static struct locomo_dev *locomolcd_dev;
 
@@ -82,7 +78,7 @@ static void locomolcd_off(int comadj)
 
 void locomolcd_power(int on)
 {
-       int comadj = 118;
+       int comadj = sharpsl_param.comadj;
        unsigned long flags;
 
        local_irq_save(flags);
@@ -93,11 +89,12 @@ void locomolcd_power(int on)
        }
 
        /* read comadj */
-#ifdef CONFIG_MACH_POODLE
-       comadj = 118;
-#else
-       comadj = 128;
-#endif
+       if (comadj == -1) {
+               if (machine_is_poodle())
+                       comadj = 118;
+               if (machine_is_collie())
+                       comadj = 128;
+       }
 
        if (on)
                locomolcd_on(comadj);
index e0dbdfc0c8b4289178d5dff1419992acd325cb78..66d6f2f0a219595833f425faa80fc16676b7c0dd 100644 (file)
@@ -2622,7 +2622,7 @@ static int __init cirrusfb_init(void)
 #endif
 
 #ifdef CONFIG_ZORRO
-       error |= zorro_module_init(&cirrusfb_zorro_driver);
+       error |= zorro_register_driver(&cirrusfb_zorro_driver);
 #endif
 #ifdef CONFIG_PCI
        error |= pci_register_driver(&cirrusfb_pci_driver);
index bebdac59d231330c353940a009ba612807f4de37..abd920a663a04a2fbbfd8446c1183af83ebf7228 100644 (file)
@@ -386,7 +386,9 @@ int __init hpfb_init(void)
        if (fb_get_options("hpfb", NULL))
                return -ENODEV;
 
-       dio_module_init(&hpfb_driver);
+       err = dio_register_driver(&hpfb_driver);
+       if (err)
+               return err;
 
        fs = get_fs();
        set_fs(KERNEL_DS);
index 0e78ddc81583dfe3a42b1ef2158346ed39699de5..52c18a35fb411d0cd5c6f8b9c3d81010195ddc2a 100644 (file)
@@ -3532,26 +3532,26 @@ int __init pm3fb_init(void)
 MODULE_AUTHOR("Romain Dolbeau");
 MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
 static char *mode[PM3_MAX_BOARD];
-MODULE_PARM(mode,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+module_param_array(mode, charp, NULL, 0);
 MODULE_PARM_DESC(mode,"video mode");
-MODULE_PARM(disable,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+module_param_array(disable, short, NULL, 0);
 MODULE_PARM_DESC(disable,"disable board");
 static short off[PM3_MAX_BOARD];
-MODULE_PARM(off,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+module_param_array(off, short, NULL, 0);
 MODULE_PARM_DESC(off,"disable board");
 static char *pciid[PM3_MAX_BOARD];
-MODULE_PARM(pciid,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+module_param_array(pciid, charp, NULL, 0);
 MODULE_PARM_DESC(pciid,"board PCI Id");
-MODULE_PARM(noaccel,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+module_param_array(noaccel, short, NULL, 0);
 MODULE_PARM_DESC(noaccel,"disable accel");
 static char *font[PM3_MAX_BOARD];
-MODULE_PARM(font,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
+module_param_array(font, charp, NULL, 0);
 MODULE_PARM_DESC(font,"choose font");
-MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+module_param(depth, short, NULL, 0);
 MODULE_PARM_DESC(depth,"boot-time depth");
-MODULE_PARM(printtimings, "h");
+module_param(printtimings, short, NULL, 0);
 MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
-MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+module_param(forcesize, short, NULL, 0);
 MODULE_PARM_DESC(forcesize, "force specified memory size");
 /*
 MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
index fcbee748c59227b2f344ab483be2558d93e749c5..067c07be928ce3a27512731799b14081a8cbd272 100644 (file)
@@ -65,22 +65,17 @@ static int zorro_device_probe(struct device *dev)
      *  @drv: the driver structure to register
      *
      *  Adds the driver structure to the list of registered drivers
-     *  Returns the number of Zorro devices which were claimed by the driver
-     *  during registration.  The driver remains registered even if the
-     *  return value is zero.
+     *  Returns zero or a negative error value.
      */
 
 int zorro_register_driver(struct zorro_driver *drv)
 {
-       int count = 0;
-
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &zorro_bus_type;
 
        /* register with core */
-       count = driver_register(&drv->driver);
-       return count ? count : 1;
+       return driver_register(&drv->driver);
 }
 
 
diff --git a/fs/9p/9p.c b/fs/9p/9p.c
deleted file mode 100644 (file)
index c148e6b..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- *  linux/fs/9p/9p.c
- *
- *  This file contains functions to perform synchronous 9P calls
- *
- *  Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the 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:
- *  Free Software Foundation
- *  51 Franklin Street, Fifth Floor
- *  Boston, MA  02111-1301  USA
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/idr.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
-#include "mux.h"
-
-/**
- * v9fs_t_version - negotiate protocol parameters with sever
- * @v9ses: 9P2000 session information
- * @msize: requested max size packet
- * @version: requested version.extension string
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
-              char *version, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
-       tc = v9fs_create_tversion(msize, version);
-
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_attach - mount the server
- * @v9ses: 9P2000 session information
- * @uname: user name doing the attach
- * @aname: remote name being attached to
- * @fid: mount fid to attatch to root node
- * @afid: authentication fid (in this case result key)
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
-             u32 fid, u32 afid, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall* tc;
-
-       dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
-               aname, fid, afid);
-
-       tc = v9fs_create_tattach(fid, afid, uname, aname);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
-       struct v9fs_fcall *rc, int err)
-{
-       int fid;
-       struct v9fs_session_info *v9ses;
-
-       if (err)
-               return;
-
-       fid = tc->params.tclunk.fid;
-       kfree(tc);
-
-       if (!rc)
-               return;
-
-       v9ses = a;
-       if (rc->id == RCLUNK)
-               v9fs_put_idpool(fid, &v9ses->fidpool);
-
-       kfree(rc);
-}
-
-/**
- * v9fs_t_clunk - release a fid (finish a transaction)
- * @v9ses: 9P2000 session information
- * @fid: fid to release
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
-{
-       int ret;
-       struct v9fs_fcall *tc, *rc;
-
-       dprintk(DEBUG_9P, "fid %d\n", fid);
-
-       rc = NULL;
-       tc = v9fs_create_tclunk(fid);
-       if (!IS_ERR(tc))
-               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
-       else
-               ret = PTR_ERR(tc);
-
-       if (ret)
-               dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
-
-       v9fs_t_clunk_cb(v9ses, tc, rc, ret);
-       return ret;
-}
-
-#if 0
-/**
- * v9fs_v9fs_t_flush - flush a pending transaction
- * @v9ses: 9P2000 session information
- * @tag: tid to release
- *
- */
-
-int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
-
-       tc = v9fs_create_tflush(oldtag);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-#endif  /*  0  */
-
-/**
- * v9fs_t_stat - read a file's meta-data
- * @v9ses: 9P2000 session information
- * @fid: fid pointing to file or directory to get info about
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "fid %d\n", fid);
-
-       ret = -ENOMEM;
-       tc = v9fs_create_tstat(fid);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_wstat - write a file's meta-data
- * @v9ses: 9P2000 session information
- * @fid: fid pointing to file or directory to write info about
- * @stat: metadata
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
-            struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "fid %d\n", fid);
-
-       tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_walk - walk a fid to a new file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to walk
- * @newfid: new fid (for clone operations)
- * @name: path to walk fid to
- * @fcall: pointer to response fcall
- *
- */
-
-/* TODO: support multiple walk */
-
-int
-v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
-           char *name, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-       int nwname;
-
-       dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
-
-       if (name)
-               nwname = 1;
-       else
-               nwname = 0;
-
-       tc = v9fs_create_twalk(fid, newfid, nwname, &name);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_open - open a file
- *
- * @v9ses - 9P2000 session information
- * @fid - fid to open
- * @mode - mode to open file (R, RW, etc)
- * @fcall - pointer to response fcall
- *
- */
-
-int
-v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
-           struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
-
-       tc = v9fs_create_topen(fid, mode);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_remove - remove a file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to remove
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
-             struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "fid %d\n", fid);
-
-       tc = v9fs_create_tremove(fid);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_create - create a file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to create
- * @name: name of the file or directory to create
- * @perm: permissions to create with
- * @mode: mode to open file (R, RW, etc)
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
-             u32 perm, u8 mode, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc;
-
-       dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
-               fid, name, perm, mode);
-
-       tc = v9fs_create_tcreate(fid, name, perm, mode);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_read - read data
- * @v9ses: 9P2000 session information
- * @fid: fid to read from
- * @offset: offset to start read at
- * @count: how many bytes to read
- * @fcall: pointer to response fcall (with data)
- *
- */
-
-int
-v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
-           u32 count, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc, *rc;
-
-       dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
-               (long long unsigned) offset, count);
-
-       tc = v9fs_create_tread(fid, offset, count);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
-               if (!ret)
-                       ret = rc->params.rread.count;
-               if (rcp)
-                       *rcp = rc;
-               else
-                       kfree(rc);
-
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
-/**
- * v9fs_t_write - write data
- * @v9ses: 9P2000 session information
- * @fid: fid to write to
- * @offset: offset to start write at
- * @count: how many bytes to write
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
-       const char __user *data, struct v9fs_fcall **rcp)
-{
-       int ret;
-       struct v9fs_fcall *tc, *rc;
-
-       dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
-               (long long unsigned) offset, count);
-
-       tc = v9fs_create_twrite(fid, offset, count, data);
-       if (!IS_ERR(tc)) {
-               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
-
-               if (!ret)
-                       ret = rc->params.rwrite.count;
-               if (rcp)
-                       *rcp = rc;
-               else
-                       kfree(rc);
-
-               kfree(tc);
-       } else
-               ret = PTR_ERR(tc);
-
-       return ret;
-}
-
index 95d72aec1c1a0a6ef4b2538a90e7b414cdf212e7..94e2f92ab2e81c754d1af016931b3ed342786498 100644 (file)
@@ -8,9 +8,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -235,6 +234,7 @@ struct Tcreate {
        struct v9fs_str name;
        u32 perm;
        u8 mode;
+       struct v9fs_str extension;
 };
 
 struct Rcreate {
@@ -364,7 +364,7 @@ int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
                  struct v9fs_fcall **rcall);
 
 int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
-                 u32 perm, u8 mode, struct v9fs_fcall **rcall);
+       u32 perm, u8 mode, char *extension, struct v9fs_fcall **rcall);
 
 int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
                u64 offset, u32 count, struct v9fs_fcall **rcall);
@@ -372,3 +372,4 @@ int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
 int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
                 u32 count, const char __user * data,
                 struct v9fs_fcall **rcall);
+int v9fs_printfcall(char *, int, struct v9fs_fcall *, int);
index 2f4ce43f7b6c57e8fdb6bcd14143b8cc77f63288..87897f84dfb6300a5f9ccce73f59f97d77c7a73e 100644 (file)
@@ -1,10 +1,9 @@
-obj-$(CONFIG_9P_FS) := 9p2000.o
+obj-$(CONFIG_9P_FS) := 9p.o
 
-9p2000-objs := \
+9p-objs := \
        trans_fd.o \
-       trans_sock.o \
        mux.o \
-       9p.o \
+       fcall.o \
        conv.o \
        vfs_super.o \
        vfs_inode.o \
@@ -14,5 +13,6 @@ obj-$(CONFIG_9P_FS) := 9p2000.o
        vfs_dentry.o \
        error.o \
        v9fs.o \
-       fid.o
+       fid.o \
+       fcprint.o
 
index bba8171424656e1c9f468f366c323c7b0a4dece6..a767e05b60bf3d03eb9438344246be3bdc71bbfc 100644 (file)
@@ -8,9 +8,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -666,7 +665,8 @@ struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
        return fc;
 }
 
-struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
+struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
+       char *extension, int extended)
 {
        int size;
        struct v9fs_fcall *fc;
@@ -674,6 +674,9 @@ struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
        struct cbuf *bufp = &buffer;
 
        size = 4 + 2 + strlen(name) + 4 + 1;    /* fid[4] name[s] perm[4] mode[1] */
+       if (extended && extension!=NULL)
+               size += 2 + strlen(extension);  /* extension[s] */
+
        fc = v9fs_create_common(bufp, size, TCREATE);
        if (IS_ERR(fc))
                goto error;
@@ -682,6 +685,8 @@ struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode)
        v9fs_put_str(bufp, name, &fc->params.tcreate.name);
        v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
        v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
+       if (extended)
+               v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
 
        if (buf_check_overflow(bufp)) {
                kfree(fc);
index f5896628dae4dd7c258ba429daf13413b0344b9d..dd5b6b1b610f09aa3e864cce39aa7e8413bd1341 100644 (file)
@@ -8,9 +8,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -39,7 +38,8 @@ struct v9fs_fcall *v9fs_create_tflush(u16 oldtag);
 struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
        char **wnames);
 struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode);
-struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode);
+struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
+       char *extension, int extended);
 struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count);
 struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
        const char __user *data);
index fe551032788b68b17f146174d36c6479733a0836..4228c0bb3c32345434efc90695730afabcd805fc 100644 (file)
@@ -5,9 +5,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -30,6 +29,7 @@
 #define DEBUG_MUX              (1<<5)
 #define DEBUG_TRANS            (1<<6)
 #define DEBUG_SLABS            (1<<7)
+#define DEBUG_FCALL            (1<<8)
 
 #define DEBUG_DUMP_PKT         0
 
index e4b6f8f38b6fbcbe3fd59fcdce526d1e5a8eeabe..981fe8ecd78045b315c1709502590d50dd6fb213 100644 (file)
@@ -11,9 +11,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index a9794e85fe51015383736e290ad4b57e44658c89..5f3ca522b3166c45d927c9afe6ac3bab047258aa 100644 (file)
@@ -12,9 +12,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c
new file mode 100644 (file)
index 0000000..71742ba
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ *  linux/fs/9p/fcall.c
+ *
+ *  This file contains functions to perform synchronous 9P calls
+ *
+ *  Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
+ *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ *  Free Software Foundation
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02111-1301  USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+
+#include "debug.h"
+#include "v9fs.h"
+#include "9p.h"
+#include "conv.h"
+#include "mux.h"
+
+/**
+ * v9fs_t_version - negotiate protocol parameters with sever
+ * @v9ses: 9P2000 session information
+ * @msize: requested max size packet
+ * @version: requested version.extension string
+ * @fcall: pointer to response fcall pointer
+ *
+ */
+
+int
+v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
+              char *version, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
+       tc = v9fs_create_tversion(msize, version);
+
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_attach - mount the server
+ * @v9ses: 9P2000 session information
+ * @uname: user name doing the attach
+ * @aname: remote name being attached to
+ * @fid: mount fid to attatch to root node
+ * @afid: authentication fid (in this case result key)
+ * @fcall: pointer to response fcall pointer
+ *
+ */
+
+int
+v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
+             u32 fid, u32 afid, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall* tc;
+
+       dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
+               aname, fid, afid);
+
+       tc = v9fs_create_tattach(fid, afid, uname, aname);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
+       struct v9fs_fcall *rc, int err)
+{
+       int fid;
+       struct v9fs_session_info *v9ses;
+
+       if (err)
+               return;
+
+       fid = tc->params.tclunk.fid;
+       kfree(tc);
+
+       if (!rc)
+               return;
+
+       v9ses = a;
+       if (rc->id == RCLUNK)
+               v9fs_put_idpool(fid, &v9ses->fidpool);
+
+       kfree(rc);
+}
+
+/**
+ * v9fs_t_clunk - release a fid (finish a transaction)
+ * @v9ses: 9P2000 session information
+ * @fid: fid to release
+ * @fcall: pointer to response fcall pointer
+ *
+ */
+
+int
+v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
+{
+       int ret;
+       struct v9fs_fcall *tc, *rc;
+
+       dprintk(DEBUG_9P, "fid %d\n", fid);
+
+       rc = NULL;
+       tc = v9fs_create_tclunk(fid);
+       if (!IS_ERR(tc))
+               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
+       else
+               ret = PTR_ERR(tc);
+
+       if (ret)
+               dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
+
+       v9fs_t_clunk_cb(v9ses, tc, rc, ret);
+       return ret;
+}
+
+#if 0
+/**
+ * v9fs_v9fs_t_flush - flush a pending transaction
+ * @v9ses: 9P2000 session information
+ * @tag: tag to release
+ *
+ */
+int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
+
+       tc = v9fs_create_tflush(oldtag);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+#endif
+
+/**
+ * v9fs_t_stat - read a file's meta-data
+ * @v9ses: 9P2000 session information
+ * @fid: fid pointing to file or directory to get info about
+ * @fcall: pointer to response fcall
+ *
+ */
+
+int
+v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "fid %d\n", fid);
+
+       ret = -ENOMEM;
+       tc = v9fs_create_tstat(fid);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_wstat - write a file's meta-data
+ * @v9ses: 9P2000 session information
+ * @fid: fid pointing to file or directory to write info about
+ * @stat: metadata
+ * @fcall: pointer to response fcall
+ *
+ */
+
+int
+v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
+            struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "fid %d\n", fid);
+
+       tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_walk - walk a fid to a new file or directory
+ * @v9ses: 9P2000 session information
+ * @fid: fid to walk
+ * @newfid: new fid (for clone operations)
+ * @name: path to walk fid to
+ * @fcall: pointer to response fcall
+ *
+ */
+
+/* TODO: support multiple walk */
+
+int
+v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
+           char *name, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+       int nwname;
+
+       dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
+
+       if (name)
+               nwname = 1;
+       else
+               nwname = 0;
+
+       tc = v9fs_create_twalk(fid, newfid, nwname, &name);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_open - open a file
+ *
+ * @v9ses - 9P2000 session information
+ * @fid - fid to open
+ * @mode - mode to open file (R, RW, etc)
+ * @fcall - pointer to response fcall
+ *
+ */
+
+int
+v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
+           struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
+
+       tc = v9fs_create_topen(fid, mode);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_remove - remove a file or directory
+ * @v9ses: 9P2000 session information
+ * @fid: fid to remove
+ * @fcall: pointer to response fcall
+ *
+ */
+
+int
+v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
+             struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "fid %d\n", fid);
+
+       tc = v9fs_create_tremove(fid);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_create - create a file or directory
+ * @v9ses: 9P2000 session information
+ * @fid: fid to create
+ * @name: name of the file or directory to create
+ * @perm: permissions to create with
+ * @mode: mode to open file (R, RW, etc)
+ * @fcall: pointer to response fcall
+ *
+ */
+
+int
+v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, u32 perm,
+       u8 mode, char *extension, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc;
+
+       dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
+               fid, name, perm, mode);
+
+       tc = v9fs_create_tcreate(fid, name, perm, mode, extension,
+               v9ses->extended);
+
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_read - read data
+ * @v9ses: 9P2000 session information
+ * @fid: fid to read from
+ * @offset: offset to start read at
+ * @count: how many bytes to read
+ * @fcall: pointer to response fcall (with data)
+ *
+ */
+
+int
+v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
+           u32 count, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc, *rc;
+
+       dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
+               (long long unsigned) offset, count);
+
+       tc = v9fs_create_tread(fid, offset, count);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
+               if (!ret)
+                       ret = rc->params.rread.count;
+               if (rcp)
+                       *rcp = rc;
+               else
+                       kfree(rc);
+
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
+/**
+ * v9fs_t_write - write data
+ * @v9ses: 9P2000 session information
+ * @fid: fid to write to
+ * @offset: offset to start write at
+ * @count: how many bytes to write
+ * @fcall: pointer to response fcall
+ *
+ */
+
+int
+v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
+       const char __user *data, struct v9fs_fcall **rcp)
+{
+       int ret;
+       struct v9fs_fcall *tc, *rc;
+
+       dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
+               (long long unsigned) offset, count);
+
+       tc = v9fs_create_twrite(fid, offset, count, data);
+       if (!IS_ERR(tc)) {
+               ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
+
+               if (!ret)
+                       ret = rc->params.rwrite.count;
+               if (rcp)
+                       *rcp = rc;
+               else
+                       kfree(rc);
+
+               kfree(tc);
+       } else
+               ret = PTR_ERR(tc);
+
+       return ret;
+}
+
diff --git a/fs/9p/fcprint.c b/fs/9p/fcprint.c
new file mode 100644 (file)
index 0000000..583e827
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ *  linux/fs/9p/fcprint.c
+ *
+ *  Print 9P call.
+ *
+ *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to:
+ *  Free Software Foundation
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02111-1301  USA
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+
+#include "debug.h"
+#include "v9fs.h"
+#include "9p.h"
+#include "mux.h"
+
+static int
+v9fs_printqid(char *buf, int buflen, struct v9fs_qid *q)
+{
+       int n;
+       char b[10];
+
+       n = 0;
+       if (q->type & V9FS_QTDIR)
+               b[n++] = 'd';
+       if (q->type & V9FS_QTAPPEND)
+               b[n++] = 'a';
+       if (q->type & V9FS_QTAUTH)
+               b[n++] = 'A';
+       if (q->type & V9FS_QTEXCL)
+               b[n++] = 'l';
+       if (q->type & V9FS_QTTMP)
+               b[n++] = 't';
+       if (q->type & V9FS_QTSYMLINK)
+               b[n++] = 'L';
+       b[n] = '\0';
+
+       return scnprintf(buf, buflen, "(%.16llx %x %s)", (long long int) q->path,
+               q->version, b);
+}
+
+static int
+v9fs_printperm(char *buf, int buflen, int perm)
+{
+       int n;
+       char b[15];
+
+       n = 0;
+       if (perm & V9FS_DMDIR)
+               b[n++] = 'd';
+       if (perm & V9FS_DMAPPEND)
+               b[n++] = 'a';
+       if (perm & V9FS_DMAUTH)
+               b[n++] = 'A';
+       if (perm & V9FS_DMEXCL)
+               b[n++] = 'l';
+       if (perm & V9FS_DMTMP)
+               b[n++] = 't';
+       if (perm & V9FS_DMDEVICE)
+               b[n++] = 'D';
+       if (perm & V9FS_DMSOCKET)
+               b[n++] = 'S';
+       if (perm & V9FS_DMNAMEDPIPE)
+               b[n++] = 'P';
+       if (perm & V9FS_DMSYMLINK)
+               b[n++] = 'L';
+       b[n] = '\0';
+
+       return scnprintf(buf, buflen, "%s%03o", b, perm&077);
+}
+
+static int
+v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended)
+{
+       int n;
+
+       n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len,
+               st->name.str, st->uid.len, st->uid.str);
+       if (extended)
+               n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid);
+
+       n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str);
+       if (extended)
+               n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid);
+
+       n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str);
+       if (extended)
+               n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
+
+       n += scnprintf(buf+n, buflen-n, " q ");
+       n += v9fs_printqid(buf+n, buflen-n, &st->qid);
+       n += scnprintf(buf+n, buflen-n, " m ");
+       n += v9fs_printperm(buf+n, buflen-n, st->mode);
+       n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
+               st->atime, st->mtime, (long long int) st->length);
+
+       if (extended)
+               n += scnprintf(buf+n, buflen-n, " ext '%.*s'",
+                       st->extension.len, st->extension.str);
+
+       return n;
+}
+
+static int
+v9fs_dumpdata(char *buf, int buflen, u8 *data, int datalen)
+{
+       int i, n;
+
+       i = n = 0;
+       while (i < datalen) {
+               n += scnprintf(buf + n, buflen - n, "%02x", data[i]);
+               if (i%4 == 3)
+                       n += scnprintf(buf + n, buflen - n, " ");
+               if (i%32 == 31)
+                       n += scnprintf(buf + n, buflen - n, "\n");
+
+               i++;
+       }
+       n += scnprintf(buf + n, buflen - n, "\n");
+
+       return n;
+}
+
+static int
+v9fs_printdata(char *buf, int buflen, u8 *data, int datalen)
+{
+       return v9fs_dumpdata(buf, buflen, data, datalen<16?datalen:16);
+}
+
+int
+v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
+{
+       int i, ret, type, tag;
+
+       if (!fc)
+               return scnprintf(buf, buflen, "<NULL>");
+
+       type = fc->id;
+       tag = fc->tag;
+
+       ret = 0;
+       switch (type) {
+       case TVERSION:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Tversion tag %u msize %u version '%.*s'", tag,
+                       fc->params.tversion.msize, fc->params.tversion.version.len,
+                       fc->params.tversion.version.str);
+               break;
+
+       case RVERSION:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Rversion tag %u msize %u version '%.*s'", tag,
+                       fc->params.rversion.msize, fc->params.rversion.version.len,
+                       fc->params.rversion.version.str);
+               break;
+
+       case TAUTH:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
+                       fc->params.tauth.afid, fc->params.tauth.uname.len,
+                       fc->params.tauth.uname.str, fc->params.tauth.aname.len,
+                       fc->params.tauth.aname.str);
+               break;
+
+       case RAUTH:
+               ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
+               v9fs_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
+               break;
+
+       case TATTACH:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'",
+                       tag, fc->params.tattach.fid, fc->params.tattach.afid,
+                       fc->params.tattach.uname.len, fc->params.tattach.uname.str,
+                       fc->params.tattach.aname.len, fc->params.tattach.aname.str);
+               break;
+
+       case RATTACH:
+               ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ", tag);
+               v9fs_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
+               break;
+
+       case RERROR:
+               ret += scnprintf(buf+ret, buflen-ret, "Rerror tag %u ename '%.*s'",
+                       tag, fc->params.rerror.error.len,
+                       fc->params.rerror.error.str);
+               if (extended)
+                       ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
+                               fc->params.rerror.errno);
+               break;
+
+       case TFLUSH:
+               ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
+                       tag, fc->params.tflush.oldtag);
+               break;
+
+       case RFLUSH:
+               ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
+               break;
+
+       case TWALK:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Twalk tag %u fid %d newfid %d nwname %d", tag,
+                       fc->params.twalk.fid, fc->params.twalk.newfid,
+                       fc->params.twalk.nwname);
+               for(i = 0; i < fc->params.twalk.nwname; i++)
+                       ret += scnprintf(buf+ret, buflen-ret," '%.*s'",
+                               fc->params.twalk.wnames[i].len,
+                               fc->params.twalk.wnames[i].str);
+               break;
+
+       case RWALK:
+               ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
+                       tag, fc->params.rwalk.nwqid);
+               for(i = 0; i < fc->params.rwalk.nwqid; i++)
+                       ret += v9fs_printqid(buf+ret, buflen-ret,
+                               &fc->params.rwalk.wqids[i]);
+               break;
+
+       case TOPEN:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Topen tag %u fid %d mode %d", tag,
+                       fc->params.topen.fid, fc->params.topen.mode);
+               break;
+
+       case ROPEN:
+               ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
+               ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
+               ret += scnprintf(buf+ret, buflen-ret," iounit %d",
+                       fc->params.ropen.iounit);
+               break;
+
+       case TCREATE:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Tcreate tag %u fid %d name '%.*s' perm ", tag,
+                       fc->params.tcreate.fid, fc->params.tcreate.name.len,
+                       fc->params.tcreate.name.str);
+
+               ret += v9fs_printperm(buf+ret, buflen-ret, fc->params.tcreate.perm);
+               ret += scnprintf(buf+ret, buflen-ret, " mode %d",
+                       fc->params.tcreate.mode);
+               break;
+
+       case RCREATE:
+               ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
+               ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.rcreate.qid);
+               ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
+                       fc->params.rcreate.iounit);
+               break;
+
+       case TREAD:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Tread tag %u fid %d offset %lld count %u", tag,
+                       fc->params.tread.fid,
+                       (long long int) fc->params.tread.offset,
+                       fc->params.tread.count);
+               break;
+
+       case RREAD:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Rread tag %u count %u data ", tag,
+                       fc->params.rread.count);
+               ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.rread.data,
+                       fc->params.rread.count);
+               break;
+
+       case TWRITE:
+               ret += scnprintf(buf+ret, buflen-ret,
+                       "Twrite tag %u fid %d offset %lld count %u data ",
+                       tag, fc->params.twrite.fid,
+                       (long long int) fc->params.twrite.offset,
+                       fc->params.twrite.count);
+               ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
+                       fc->params.twrite.count);
+               break;
+
+       case RWRITE:
+               ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
+                       tag, fc->params.rwrite.count);
+               break;
+
+       case TCLUNK:
+               ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
+                       tag, fc->params.tclunk.fid);
+               break;
+
+       case RCLUNK:
+               ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
+               break;
+
+       case TREMOVE:
+               ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
+                       tag, fc->params.tremove.fid);
+               break;
+
+       case RREMOVE:
+               ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
+               break;
+
+       case TSTAT:
+               ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
+                       tag, fc->params.tstat.fid);
+               break;
+
+       case RSTAT:
+               ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
+               ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
+                       extended);
+               break;
+
+       case TWSTAT:
+               ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
+                       tag, fc->params.twstat.fid);
+               ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.twstat.stat,
+                       extended);
+               break;
+
+       case RWSTAT:
+               ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
+               break;
+
+       default:
+               ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type);
+               break;
+       }
+
+       return ret;
+}
index c4d13bf904d2319105f5731004555a76f73e88b6..b7608af07ce8b44db2c3378f0a1b3f49efb65191 100644 (file)
@@ -4,9 +4,8 @@
  *  Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index 1fc2dd08d75acdc68ee2efb47f9e4fcfe6b4f177..aa974d6875c34992be824535b3db0e5e913884aa 100644 (file)
@@ -4,9 +4,8 @@
  *  Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index e2ae60adda99cb8f814f20d18b0fe5e59d0f98b3..3e5b124a72123d4c50a99c44351d87a0a21d5388 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -70,7 +69,7 @@ struct v9fs_mux_data {
        int msize;
        unsigned char *extended;
        struct v9fs_transport *trans;
-       struct v9fs_idpool tidpool;
+       struct v9fs_idpool tagpool;
        int err;
        wait_queue_head_t equeue;
        struct list_head req_list;
@@ -280,8 +279,8 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
        m->msize = msize;
        m->extended = extended;
        m->trans = trans;
-       idr_init(&m->tidpool.pool);
-       init_MUTEX(&m->tidpool.lock);
+       idr_init(&m->tagpool.pool);
+       init_MUTEX(&m->tagpool.lock);
        m->err = 0;
        init_waitqueue_head(&m->equeue);
        INIT_LIST_HEAD(&m->req_list);
@@ -635,6 +634,14 @@ static void v9fs_read_work(void *a)
                        goto error;
                }
 
+               if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) {
+                       char buf[150];
+
+                       v9fs_printfcall(buf, sizeof(buf), m->rcall,
+                               *m->extended);
+                       printk(KERN_NOTICE ">>> %p %s\n", m, buf);
+               }
+
                rcall = m->rcall;
                rbuf = m->rbuf;
                if (m->rpos > n) {
@@ -740,6 +747,13 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
 
        v9fs_set_tag(tc, n);
 
+       if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) {
+               char buf[150];
+
+               v9fs_printfcall(buf, sizeof(buf), tc, *m->extended);
+               printk(KERN_NOTICE "<<< %p %s\n", m, buf);
+       }
+
        req->tag = n;
        req->tcall = tc;
        req->rcall = NULL;
@@ -965,7 +979,7 @@ static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
 {
        int tag;
 
-       tag = v9fs_get_idpool(&m->tidpool);
+       tag = v9fs_get_idpool(&m->tagpool);
        if (tag < 0)
                return V9FS_NOTAG;
        else
@@ -974,6 +988,6 @@ static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
 
 static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag)
 {
-       if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tidpool))
-               v9fs_put_idpool(tag, &m->tidpool);
+       if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tagpool))
+               v9fs_put_idpool(tag, &m->tagpool);
 }
index 17144fdfa11b4cb3ebfba6f91624958c8cf6bac6..e90bfd32ea42335ebd411e0d82423b34a38e5d0d 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index 5b2ce21b10fab55b6bf6e5db54b615d3c961c2ea..94e0a7fd9fc2c30b6954001620a975005a742e29 100644 (file)
@@ -1,15 +1,16 @@
 /*
  * linux/fs/9p/trans_fd.c
  *
- * File Descriptor Transport Layer
+ * Fd transport layer.  Includes deprecated socket layer.
  *
- *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- *  Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
+ *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
+ *  Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com>
+ *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,6 +26,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/in.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/ipv6.h>
 #include "v9fs.h"
 #include "transport.h"
 
+#define V9FS_PORT 564
+
 struct v9fs_trans_fd {
-       struct file *in_file;
-       struct file *out_file;
+       struct file *rd;
+       struct file *wr;
 };
 
 /**
- * v9fs_fd_recv - receive from a socket
+ * v9fs_fd_read- read from a fd
  * @v9ses: session information
  * @v: buffer to receive data into
  * @len: size of receive buffer
  *
  */
-
-static int v9fs_fd_recv(struct v9fs_transport *trans, void *v, int len)
+static int v9fs_fd_read(struct v9fs_transport *trans, void *v, int len)
 {
-       struct v9fs_trans_fd *ts = trans ? trans->priv : NULL;
+       int ret;
+       struct v9fs_trans_fd *ts;
 
-       if (!trans || trans->status != Connected || !ts)
-               return -EIO;
+       if (!trans || trans->status == Disconnected || !(ts = trans->priv))
+               return -EREMOTEIO;
 
-       return kernel_read(ts->in_file, ts->in_file->f_pos, v, len);
+       if (!(ts->rd->f_flags & O_NONBLOCK))
+               dprintk(DEBUG_ERROR, "blocking read ...\n");
+
+       ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
+       if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+               trans->status = Disconnected;
+       return ret;
 }
 
 /**
- * v9fs_fd_send - send to a socket
+ * v9fs_fd_write - write to a socket
  * @v9ses: session information
  * @v: buffer to send data from
  * @len: size of send buffer
  *
  */
-
-static int v9fs_fd_send(struct v9fs_transport *trans, void *v, int len)
+static int v9fs_fd_write(struct v9fs_transport *trans, void *v, int len)
 {
-       struct v9fs_trans_fd *ts = trans ? trans->priv : NULL;
-       mm_segment_t oldfs = get_fs();
-       int ret = 0;
+       int ret;
+       mm_segment_t oldfs;
+       struct v9fs_trans_fd *ts;
 
-       if (!trans || trans->status != Connected || !ts)
-               return -EIO;
+       if (!trans || trans->status == Disconnected || !(ts = trans->priv))
+               return -EREMOTEIO;
+
+       if (!(ts->wr->f_flags & O_NONBLOCK))
+               dprintk(DEBUG_ERROR, "blocking write ...\n");
 
        oldfs = get_fs();
        set_fs(get_ds());
        /* The cast to a user pointer is valid due to the set_fs() */
-       ret = vfs_write(ts->out_file, (void __user *)v, len, &ts->out_file->f_pos);
+       ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
        set_fs(oldfs);
 
+       if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+               trans->status = Disconnected;
        return ret;
 }
 
-/**
- * v9fs_fd_init - initialize file descriptor transport
- * @v9ses: session information
- * @addr: address of server to mount
- * @data: mount options
- *
- */
-
-static int
-v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
+static unsigned int
+v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt)
 {
-       struct v9fs_trans_fd *ts = NULL;
-       struct v9fs_transport *trans = v9ses->transport;
+       int ret, n;
+       struct v9fs_trans_fd *ts;
+       mm_segment_t oldfs;
 
-       if((v9ses->wfdno == ~0) || (v9ses->rfdno == ~0)) {
-               printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
-               return -ENOPROTOOPT;
-       }
+       if (!trans || trans->status != Connected || !(ts = trans->priv))
+               return -EREMOTEIO;
 
-       ts = kmalloc(sizeof(struct v9fs_trans_fd), GFP_KERNEL);
+       if (!ts->rd->f_op || !ts->rd->f_op->poll)
+               return -EIO;
 
-       if (!ts)
-               return -ENOMEM;
+       if (!ts->wr->f_op || !ts->wr->f_op->poll)
+               return -EIO;
 
-       ts->in_file = fget( v9ses->rfdno );
-       ts->out_file = fget( v9ses->wfdno );
+       oldfs = get_fs();
+       set_fs(get_ds());
 
-       if (!ts->in_file || !ts->out_file) {
-               if (ts->in_file)
-                       fput(ts->in_file);
+       ret = ts->rd->f_op->poll(ts->rd, pt);
+       if (ret < 0)
+               goto end;
 
-               if (ts->out_file)
-                       fput(ts->out_file);
+       if (ts->rd != ts->wr) {
+               n = ts->wr->f_op->poll(ts->wr, pt);
+               if (n < 0) {
+                       ret = n;
+                       goto end;
+               }
+               ret = (ret & ~POLLOUT) | (n & ~POLLIN);
+       }
 
+      end:
+       set_fs(oldfs);
+       return ret;
+}
+
+static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd)
+{
+       struct v9fs_transport *trans = v9ses->transport;
+       struct v9fs_trans_fd *ts = kmalloc(sizeof(struct v9fs_trans_fd),
+                                          GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       ts->rd = fget(rfd);
+       ts->wr = fget(wfd);
+       if (!ts->rd || !ts->wr) {
+               if (ts->rd)
+                       fput(ts->rd);
+               if (ts->wr)
+                       fput(ts->wr);
                kfree(ts);
                return -EIO;
        }
@@ -133,84 +165,145 @@ v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
        return 0;
 }
 
-
-/**
- * v9fs_fd_close - shutdown file descriptor
- * @trans: private socket structure
- *
- */
-
-static void v9fs_fd_close(struct v9fs_transport *trans)
+static int v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr,
+                       char *data)
 {
-       struct v9fs_trans_fd *ts;
-
-       if (!trans)
-               return;
-
-       ts = xchg(&trans->priv, NULL);
+       if (v9ses->rfdno == ~0 || v9ses->wfdno == ~0) {
+               printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
+               return -ENOPROTOOPT;
+       }
 
-       if (!ts)
-               return;
+       return v9fs_fd_open(v9ses, v9ses->rfdno, v9ses->wfdno);
+}
 
-       trans->status = Disconnected;
-       if (ts->in_file)
-               fput(ts->in_file);
+static int v9fs_socket_open(struct v9fs_session_info *v9ses,
+                           struct socket *csocket)
+{
+       int fd, ret;
+
+       csocket->sk->sk_allocation = GFP_NOIO;
+       if ((fd = sock_map_fd(csocket)) < 0) {
+               eprintk(KERN_ERR, "v9fs_socket_open: failed to map fd\n");
+               ret = fd;
+             release_csocket:
+               sock_release(csocket);
+               return ret;
+       }
 
-       if (ts->out_file)
-               fput(ts->out_file);
+       if ((ret = v9fs_fd_open(v9ses, fd, fd)) < 0) {
+               sockfd_put(csocket);
+               eprintk(KERN_ERR, "v9fs_socket_open: failed to open fd\n");
+               goto release_csocket;
+       }
 
-       kfree(ts);
+       ((struct v9fs_trans_fd *)v9ses->transport->priv)->rd->f_flags |=
+           O_NONBLOCK;
+       return 0;
 }
 
-static unsigned int
-v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt)
+static int v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr,
+                        char *data)
 {
-       int ret, n;
-       struct v9fs_trans_fd *ts;
-       mm_segment_t oldfs;
+       int ret;
+       struct socket *csocket = NULL;
+       struct sockaddr_in sin_server;
+
+       sin_server.sin_family = AF_INET;
+       sin_server.sin_addr.s_addr = in_aton(addr);
+       sin_server.sin_port = htons(v9ses->port);
+       sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
+
+       if (!csocket) {
+               eprintk(KERN_ERR, "v9fs_trans_tcp: problem creating socket\n");
+               return -1;
+       }
 
-       if (!trans)
-               return -EIO;
+       ret = csocket->ops->connect(csocket,
+                                   (struct sockaddr *)&sin_server,
+                                   sizeof(struct sockaddr_in), 0);
+       if (ret < 0) {
+               eprintk(KERN_ERR,
+                       "v9fs_trans_tcp: problem connecting socket to %s\n",
+                       addr);
+               return ret;
+       }
 
-       ts = trans->priv;
-       if (trans->status != Connected || !ts)
-               return -EIO;
+       return v9fs_socket_open(v9ses, csocket);
+}
 
-       oldfs = get_fs();
-       set_fs(get_ds());
+static int
+v9fs_unix_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
+{
+       int ret;
+       struct socket *csocket;
+       struct sockaddr_un sun_server;
+
+       if (strlen(addr) > UNIX_PATH_MAX) {
+               eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
+                       addr);
+               return -ENAMETOOLONG;
+       }
 
-       if (!ts->in_file->f_op || !ts->in_file->f_op->poll) {
-               ret = -EIO;
-               goto end;
+       sun_server.sun_family = PF_UNIX;
+       strcpy(sun_server.sun_path, addr);
+       sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
+       ret = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
+                       sizeof(struct sockaddr_un) - 1, 0);
+       if (ret < 0) {
+               eprintk(KERN_ERR,
+                       "v9fs_trans_unix: problem connecting socket: %s: %d\n",
+                       addr, ret);
+               return ret;
        }
 
-       ret = ts->in_file->f_op->poll(ts->in_file, pt);
+       return v9fs_socket_open(v9ses, csocket);
+}
 
-       if (ts->out_file != ts->in_file) {
-               if (!ts->out_file->f_op || !ts->out_file->f_op->poll) {
-                       ret = -EIO;
-                       goto end;
-               }
+/**
+ * v9fs_sock_close - shutdown socket
+ * @trans: private socket structure
+ *
+ */
+static void v9fs_fd_close(struct v9fs_transport *trans)
+{
+       struct v9fs_trans_fd *ts;
 
-               n = ts->out_file->f_op->poll(ts->out_file, pt);
+       if (!trans)
+               return;
 
-               ret &= ~POLLOUT;
-               n &= ~POLLIN;
+       ts = xchg(&trans->priv, NULL);
 
-               ret |= n;
-       }
+       if (!ts)
+               return;
 
-end:
-       set_fs(oldfs);
-       return ret;
+       trans->status = Disconnected;
+       if (ts->rd)
+               fput(ts->rd);
+       if (ts->wr)
+               fput(ts->wr);
+       kfree(ts);
 }
 
-
 struct v9fs_transport v9fs_trans_fd = {
        .init = v9fs_fd_init,
-       .write = v9fs_fd_send,
-       .read = v9fs_fd_recv,
+       .write = v9fs_fd_write,
+       .read = v9fs_fd_read,
        .close = v9fs_fd_close,
        .poll = v9fs_fd_poll,
 };
 
+struct v9fs_transport v9fs_trans_tcp = {
+       .init = v9fs_tcp_init,
+       .write = v9fs_fd_write,
+       .read = v9fs_fd_read,
+       .close = v9fs_fd_close,
+       .poll = v9fs_fd_poll,
+};
+
+struct v9fs_transport v9fs_trans_unix = {
+       .init = v9fs_unix_init,
+       .write = v9fs_fd_write,
+       .read = v9fs_fd_read,
+       .close = v9fs_fd_close,
+       .poll = v9fs_fd_poll,
+};
diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c
deleted file mode 100644 (file)
index 44e8306..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * linux/fs/9p/trans_socket.c
- *
- * Socket Transport Layer
- *
- *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
- *  Copyright (C) 1995, 1996 by Olaf Kirch <okir@monad.swb.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to:
- *  Free Software Foundation
- *  51 Franklin Street, Fifth Floor
- *  Boston, MA  02111-1301  USA
- *
- */
-
-#include <linux/config.h>
-#include <linux/in.h>
-#include <linux/module.h>
-#include <linux/net.h>
-#include <linux/ipv6.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/un.h>
-#include <asm/uaccess.h>
-#include <linux/inet.h>
-#include <linux/idr.h>
-#include <linux/file.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "transport.h"
-
-#define V9FS_PORT 564
-
-struct v9fs_trans_sock {
-       struct socket *s;
-       struct file *filp;
-};
-
-/**
- * v9fs_sock_recv - receive from a socket
- * @v9ses: session information
- * @v: buffer to receive data into
- * @len: size of receive buffer
- *
- */
-
-static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len)
-{
-       int ret;
-       struct v9fs_trans_sock *ts;
-
-       if (!trans || trans->status == Disconnected) {
-               dprintk(DEBUG_ERROR, "disconnected ...\n");
-               return -EREMOTEIO;
-       }
-
-       ts = trans->priv;
-
-       if (!(ts->filp->f_flags & O_NONBLOCK))
-               dprintk(DEBUG_ERROR, "blocking read ...\n");
-
-       ret = kernel_read(ts->filp, ts->filp->f_pos, v, len);
-       if (ret <= 0) {
-               if (ret != -ERESTARTSYS && ret != -EAGAIN)
-                       trans->status = Disconnected;
-       }
-
-       return ret;
-}
-
-/**
- * v9fs_sock_send - send to a socket
- * @v9ses: session information
- * @v: buffer to send data from
- * @len: size of send buffer
- *
- */
-
-static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len)
-{
-       int ret;
-       mm_segment_t oldfs;
-       struct v9fs_trans_sock *ts;
-
-       if (!trans || trans->status == Disconnected) {
-               dprintk(DEBUG_ERROR, "disconnected ...\n");
-               return -EREMOTEIO;
-       }
-
-       ts = trans->priv;
-       if (!ts) {
-               dprintk(DEBUG_ERROR, "no transport ...\n");
-               return -EREMOTEIO;
-       }
-
-       if (!(ts->filp->f_flags & O_NONBLOCK))
-               dprintk(DEBUG_ERROR, "blocking write ...\n");
-
-       oldfs = get_fs();
-       set_fs(get_ds());
-       ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos);
-       set_fs(oldfs);
-
-       if (ret < 0) {
-               if (ret != -ERESTARTSYS)
-                       trans->status = Disconnected;
-       }
-
-       return ret;
-}
-
-static unsigned int v9fs_sock_poll(struct v9fs_transport *trans,
-       struct poll_table_struct *pt) {
-
-       int ret;
-       struct v9fs_trans_sock *ts;
-       mm_segment_t oldfs;
-
-       if (!trans) {
-               dprintk(DEBUG_ERROR, "no transport\n");
-               return -EIO;
-       }
-
-       ts = trans->priv;
-       if (trans->status != Connected || !ts) {
-               dprintk(DEBUG_ERROR, "transport disconnected: %d\n", trans->status);
-               return -EIO;
-       }
-
-       oldfs = get_fs();
-       set_fs(get_ds());
-
-       if (!ts->filp->f_op || !ts->filp->f_op->poll) {
-               dprintk(DEBUG_ERROR, "no poll operation\n");
-               ret = -EIO;
-               goto end;
-       }
-
-       ret = ts->filp->f_op->poll(ts->filp, pt);
-
-end:
-       set_fs(oldfs);
-       return ret;
-}
-
-
-/**
- * v9fs_tcp_init - initialize TCP socket
- * @v9ses: session information
- * @addr: address of server to mount
- * @data: mount options
- *
- */
-
-static int
-v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
-{
-       struct socket *csocket = NULL;
-       struct sockaddr_in sin_server;
-       int rc = 0;
-       struct v9fs_trans_sock *ts = NULL;
-       struct v9fs_transport *trans = v9ses->transport;
-       int fd;
-
-       trans->status = Disconnected;
-
-       ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL);
-
-       if (!ts)
-               return -ENOMEM;
-
-       trans->priv = ts;
-       ts->s = NULL;
-       ts->filp = NULL;
-
-       if (!addr)
-               return -EINVAL;
-
-       dprintk(DEBUG_TRANS, "Connecting to %s\n", addr);
-
-       sin_server.sin_family = AF_INET;
-       sin_server.sin_addr.s_addr = in_aton(addr);
-       sin_server.sin_port = htons(v9ses->port);
-       sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
-       rc = csocket->ops->connect(csocket,
-                                  (struct sockaddr *)&sin_server,
-                                  sizeof(struct sockaddr_in), 0);
-       if (rc < 0) {
-               eprintk(KERN_ERR,
-                       "v9fs_trans_tcp: problem connecting socket to %s\n",
-                       addr);
-               return rc;
-       }
-       csocket->sk->sk_allocation = GFP_NOIO;
-
-       fd = sock_map_fd(csocket);
-       if (fd < 0) {
-               sock_release(csocket);
-               kfree(ts);
-               trans->priv = NULL;
-               return fd;
-       }
-
-       ts->s = csocket;
-       ts->filp = fget(fd);
-       ts->filp->f_flags |= O_NONBLOCK;
-       trans->status = Connected;
-
-       return 0;
-}
-
-/**
- * v9fs_unix_init - initialize UNIX domain socket
- * @v9ses: session information
- * @dev_name: path to named pipe
- * @data: mount options
- *
- */
-
-static int
-v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name,
-              char *data)
-{
-       int rc, fd;
-       struct socket *csocket;
-       struct sockaddr_un sun_server;
-       struct v9fs_transport *trans;
-       struct v9fs_trans_sock *ts;
-
-       rc = 0;
-       csocket = NULL;
-       trans = v9ses->transport;
-
-       trans->status = Disconnected;
-
-       if (strlen(dev_name) > UNIX_PATH_MAX) {
-               eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
-                       dev_name);
-               return -ENOMEM;
-       }
-
-       ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL);
-       if (!ts)
-               return -ENOMEM;
-
-       trans->priv = ts;
-       ts->s = NULL;
-       ts->filp = NULL;
-
-       sun_server.sun_family = PF_UNIX;
-       strcpy(sun_server.sun_path, dev_name);
-       sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
-       rc = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
-               sizeof(struct sockaddr_un) - 1, 0);     /* -1 *is* important */
-       if (rc < 0) {
-               eprintk(KERN_ERR,
-                       "v9fs_trans_unix: problem connecting socket: %s: %d\n",
-                       dev_name, rc);
-               return rc;
-       }
-       csocket->sk->sk_allocation = GFP_NOIO;
-
-       fd = sock_map_fd(csocket);
-       if (fd < 0) {
-               sock_release(csocket);
-               kfree(ts);
-               trans->priv = NULL;
-               return fd;
-       }
-
-       ts->s = csocket;
-       ts->filp = fget(fd);
-       ts->filp->f_flags |= O_NONBLOCK;
-       trans->status = Connected;
-
-       return 0;
-}
-
-/**
- * v9fs_sock_close - shutdown socket
- * @trans: private socket structure
- *
- */
-
-static void v9fs_sock_close(struct v9fs_transport *trans)
-{
-       struct v9fs_trans_sock *ts;
-
-       if (!trans)
-               return;
-
-       ts = trans->priv;
-
-       if ((ts) && (ts->filp)) {
-               fput(ts->filp);
-               ts->filp = NULL;
-               ts->s = NULL;
-               trans->status = Disconnected;
-       }
-
-       kfree(ts);
-
-       trans->priv = NULL;
-}
-
-struct v9fs_transport v9fs_trans_tcp = {
-       .init = v9fs_tcp_init,
-       .write = v9fs_sock_send,
-       .read = v9fs_sock_recv,
-       .close = v9fs_sock_close,
-       .poll = v9fs_sock_poll,
-};
-
-struct v9fs_transport v9fs_trans_unix = {
-       .init = v9fs_unix_init,
-       .write = v9fs_sock_send,
-       .read = v9fs_sock_recv,
-       .close = v9fs_sock_close,
-       .poll = v9fs_sock_poll,
-};
index 91fcdb94b361be46b5f160f793e0dadfd705974c..b38a4b8a41ce822b1733d99d277dc5e391bc4910 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index 61352491ba36c0798cf6632de1c3e9e8cdb4e00a..d37416eb57919d8caa20e21b81b37b8ce4701fa9 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -51,7 +50,7 @@ enum {
        Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug,
        Opt_rfdno, Opt_wfdno,
        /* String options */
-       Opt_name, Opt_remotename,
+       Opt_uname, Opt_remotename,
        /* Options that take no arguments */
        Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd,
        /* Error token */
@@ -67,7 +66,7 @@ static match_table_t tokens = {
        {Opt_rfdno, "rfdno=%u"},
        {Opt_wfdno, "wfdno=%u"},
        {Opt_debug, "debug=%x"},
-       {Opt_name, "name=%s"},
+       {Opt_uname, "uname=%s"},
        {Opt_remotename, "aname=%s"},
        {Opt_unix, "proto=unix"},
        {Opt_tcp, "proto=tcp"},
@@ -116,7 +115,7 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
                if (!*p)
                        continue;
                token = match_token(p, tokens, args);
-               if (token < Opt_name) {
+               if (token < Opt_uname) {
                        if ((ret = match_int(&args[0], &option)) < 0) {
                                dprintk(DEBUG_ERROR,
                                        "integer field, but no integer?\n");
@@ -158,7 +157,7 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
                case Opt_fd:
                        v9ses->proto = PROTO_FD;
                        break;
-               case Opt_name:
+               case Opt_uname:
                        match_strcpy(v9ses->name, &args[0]);
                        break;
                case Opt_remotename:
@@ -289,7 +288,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
        /* set global debug level */
        v9fs_debug_level = v9ses->debug;
 
-       /* id pools that are session-dependent: FIDs and TIDs */
+       /* id pools that are session-dependent: fids and tags */
        idr_init(&v9ses->fidpool.pool);
        init_MUTEX(&v9ses->fidpool.lock);
 
index f337da7a0eec1c4c6be93307172ba5e9f7511b70..c134d104cb28f56b606d51886a7e34f93f02c378 100644 (file)
@@ -5,9 +5,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -91,6 +90,3 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses);
 #define V9FS_DEFUSER   "nobody"
 #define V9FS_DEFANAME  ""
 
-/* inital pool sizes for fids and tags */
-#define V9FS_START_FIDS 8192
-#define V9FS_START_TIDS 256
index a759278acaaeac31b50eaa08b85b5189a735913b..43c9f7de0314e8360b943746424a5d596e10236e 100644 (file)
@@ -5,9 +5,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index 8100fb5171b70d1e20c26290cd37862d1856545c..efda46fb64d9e5a0bacaa14ead4f0414e04b07f6 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index 12c9cc926b71afc45f5722fbfa70fb7b0a44ad37..062daa6000ab55a33441b8bcac7aa4375727fe14 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -51,7 +50,7 @@
  *
  */
 
-int v9fs_dentry_delete(struct dentry *dentry)
+static int v9fs_dentry_delete(struct dentry *dentry)
 {
        dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
        return 1;
index cd5eeb032d64367a950974351ba8dce0b41c8c98..766f11f1215c9545bf347dada64a725b942951fa 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
index de3a129698da7bcb3edb82045c1489f4012a4432..59e74416340775af80a41ee99ce36366c4223466 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -69,29 +68,30 @@ int v9fs_file_open(struct inode *inode, struct file *file)
 
        fid = v9fs_get_idpool(&v9ses->fidpool);
        if (fid < 0) {
-                       eprintk(KERN_WARNING, "newfid fails!\n");
-                       return -ENOSPC;
-               }
+               eprintk(KERN_WARNING, "newfid fails!\n");
+               return -ENOSPC;
+       }
 
        err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL);
        if (err < 0) {
-                       dprintk(DEBUG_ERROR, "rewalk didn't work\n");
+               dprintk(DEBUG_ERROR, "rewalk didn't work\n");
                goto put_fid;
        }
 
-       vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
-       if (vfid == NULL) {
-               dprintk(DEBUG_ERROR, "out of memory\n");
-               goto clunk_fid;
-               }
-
-               /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
-               /* translate open mode appropriately */
+       /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
+       /* translate open mode appropriately */
        omode = v9fs_uflags2omode(file->f_flags);
        err = v9fs_t_open(v9ses, fid, omode, &fcall);
        if (err < 0) {
                PRINT_FCALL_ERROR("open failed", fcall);
-               goto destroy_vfid;
+               goto clunk_fid;
+       }
+
+       vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
+       if (vfid == NULL) {
+               dprintk(DEBUG_ERROR, "out of memory\n");
+               err = -ENOMEM;
+               goto clunk_fid;
        }
 
        file->private_data = vfid;
@@ -106,15 +106,12 @@ int v9fs_file_open(struct inode *inode, struct file *file)
 
        return 0;
 
-destroy_vfid:
-       v9fs_fid_destroy(vfid);
-
 clunk_fid:
        v9fs_t_clunk(v9ses, fid);
 
 put_fid:
        v9fs_put_idpool(fid, &v9ses->fidpool);
-               kfree(fcall);
+       kfree(fcall);
 
        return err;
 }
index 651a9e14d9a9e5f53f6ba4b5a7861751cf2838dc..133db366d30659aad05be2c18a383e5722eb1f71 100644 (file)
@@ -7,9 +7,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -255,8 +254,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
 }
 
 static int
-v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name,
-       u32 perm, u8 mode, u32 *fidp, struct v9fs_qid *qid, u32 *iounit)
+v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm,
+       u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit)
 {
        u32 fid;
        int err;
@@ -271,14 +270,14 @@ v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name,
        err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall);
        if (err < 0) {
                PRINT_FCALL_ERROR("clone error", fcall);
-               goto error;
+               goto put_fid;
        }
        kfree(fcall);
 
-       err = v9fs_t_create(v9ses, fid, name, perm, mode, &fcall);
+       err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall);
        if (err < 0) {
                PRINT_FCALL_ERROR("create fails", fcall);
-               goto error;
+               goto clunk_fid;
        }
 
        if (iounit)
@@ -293,7 +292,11 @@ v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name,
        kfree(fcall);
        return 0;
 
-error:
+clunk_fid:
+       v9fs_t_clunk(v9ses, fid);
+       fid = V9FS_NOFID;
+
+put_fid:
        if (fid >= 0)
                v9fs_put_idpool(fid, &v9ses->fidpool);
 
@@ -348,7 +351,7 @@ error:
        return ERR_PTR(err);
 }
 
-struct inode *
+static struct inode *
 v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid,
        struct super_block *sb)
 {
@@ -474,7 +477,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
                flags = O_RDWR;
 
        err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
-               perm, v9fs_uflags2omode(flags), &fid, &qid, &iounit);
+               perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit);
 
        if (err)
                goto error;
@@ -550,7 +553,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
 
        err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
-               perm, V9FS_OREAD, &fid, NULL, NULL);
+               perm, V9FS_OREAD, NULL, &fid, NULL, NULL);
 
        if (err) {
                dprintk(DEBUG_ERROR, "create error %d\n", err);
@@ -1008,11 +1011,13 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
 
        /* copy extension buffer into buffer */
        if (fcall->params.rstat.stat.extension.len < buflen)
-               buflen = fcall->params.rstat.stat.extension.len;
+               buflen = fcall->params.rstat.stat.extension.len + 1;
 
-       memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
+       memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
        buffer[buflen-1] = 0;
 
+       dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len,
+               fcall->params.rstat.stat.extension.str, buffer);
        retval = buflen;
 
       FreeFcall:
@@ -1072,7 +1077,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
        if (!link)
                link = ERR_PTR(-ENOMEM);
        else {
-               len = v9fs_readlink(dentry, link, strlen(link));
+               len = v9fs_readlink(dentry, link, PATH_MAX);
 
                if (len < 0) {
                        __putname(link);
@@ -1109,10 +1114,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
        struct v9fs_session_info *v9ses;
        struct v9fs_fid *dfid, *vfid;
        struct inode *inode;
-       struct v9fs_fcall *fcall;
-       struct v9fs_wstat wstat;
 
-       fcall = NULL;
        inode = NULL;
        vfid = NULL;
        v9ses = v9fs_inode2v9ses(dir);
@@ -1125,7 +1127,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
        }
 
        err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
-               perm, V9FS_OREAD, &fid, NULL, NULL);
+               perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL);
 
        if (err)
                goto error;
@@ -1148,23 +1150,11 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
                goto error;
        }
 
-       /* issue a Twstat */
-       v9fs_blank_wstat(&wstat);
-       wstat.muid = v9ses->name;
-       wstat.extension = (char *) extension;
-       err = v9fs_t_wstat(v9ses, vfid->fid, &wstat, &fcall);
-       if (err < 0) {
-               PRINT_FCALL_ERROR("wstat error", fcall);
-               goto error;
-       }
-
-       kfree(fcall);
        dentry->d_op = &v9fs_dentry_operations;
        d_instantiate(dentry, inode);
        return 0;
 
 error:
-       kfree(fcall);
        if (vfid)
                v9fs_fid_destroy(vfid);
 
@@ -1224,7 +1214,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
        }
 
        name = __getname();
-       sprintf(name, "hardlink(%d)\n", oldfid->fid);
+       sprintf(name, "%d\n", oldfid->fid);
        retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
        __putname(name);
 
@@ -1253,6 +1243,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
                return -EINVAL;
 
        name = __getname();
+       if (!name)
+               return -ENOMEM;
        /* build extension */
        if (S_ISBLK(mode))
                sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
index d05318fa684e9bc645b1c96bfc6e12521185ab3f..b0a0ae509c00524d27dd306541b0935321766514 100644 (file)
@@ -8,9 +8,8 @@
  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  *
  *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -262,7 +261,7 @@ static struct super_operations v9fs_super_ops = {
 };
 
 struct file_system_type v9fs_fs_type = {
-       .name = "9P",
+       .name = "9p",
        .get_sb = v9fs_get_sb,
        .kill_sb = v9fs_kill_super,
        .owner = THIS_MODULE,
index aec2b1916d1b27e4bc9411212359801b8ba70386..e41e932ba489ff040fe9ed43385fc164a8dd6515 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -122,10 +122,9 @@ static int aio_setup_ring(struct kioctx *ctx)
        info->nr = 0;
        info->ring_pages = info->internal_pages;
        if (nr_pages > AIO_RING_PAGES) {
-               info->ring_pages = kmalloc(sizeof(struct page *) * nr_pages, GFP_KERNEL);
+               info->ring_pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
                if (!info->ring_pages)
                        return -ENOMEM;
-               memset(info->ring_pages, 0, sizeof(struct page *) * nr_pages);
        }
 
        info->mmap_size = nr_pages * PAGE_SIZE;
index c2eac2a50bd266889786d9eb825fdb96fa1e2d19..4349113881fbfc79e7fcf2500e2d13217e6fadc5 100644 (file)
@@ -1334,7 +1334,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
 
        i = p->state ? ffz(~p->state) + 1 : 0;
        psinfo->pr_state = i;
-       psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDTZW"[i];
+       psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];
        psinfo->pr_zomb = psinfo->pr_sname == 'Z';
        psinfo->pr_nice = task_nice(p);
        psinfo->pr_flag = p->flags;
@@ -1465,12 +1465,11 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
                read_lock(&tasklist_lock);
                do_each_thread(g,p)
                        if (current->mm == p->mm && current != p) {
-                               tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
+                               tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
                                if (!tmp) {
                                        read_unlock(&tasklist_lock);
                                        goto cleanup;
                                }
-                               memset(tmp, 0, sizeof(*tmp));
                                INIT_LIST_HEAD(&tmp->list);
                                tmp->thread = p;
                                list_add(&tmp->list, &thread_list);
index 108d56bbd0d07e58669a51ede9ff37d17d703956..69f44dcdb0b4c92f504e118a4eae080528cf68b0 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/personality.h>
 #include <linux/init.h>
 #include <linux/flat.h>
+#include <linux/syscalls.h>
 
 #include <asm/byteorder.h>
 #include <asm/system.h>
@@ -426,6 +427,8 @@ static int load_flat_file(struct linux_binprm * bprm,
        int i, rev, relocs = 0;
        loff_t fpos;
        unsigned long start_code, end_code;
+       int ret;
+       int exec_fileno;
 
        hdr = ((struct flat_hdr *) bprm->buf);          /* exec-header */
        inode = bprm->file->f_dentry->d_inode;
@@ -450,7 +453,8 @@ static int load_flat_file(struct linux_binprm * bprm,
                 */
                if (strncmp(hdr->magic, "#!", 2))
                        printk("BINFMT_FLAT: bad header magic\n");
-               return -ENOEXEC;
+               ret = -ENOEXEC;
+               goto err;
        }
 
        if (flags & FLAT_FLAG_KTRACE)
@@ -458,14 +462,16 @@ static int load_flat_file(struct linux_binprm * bprm,
 
        if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
                printk("BINFMT_FLAT: bad flat file version 0x%x (supported 0x%x and 0x%x)\n", rev, FLAT_VERSION, OLD_FLAT_VERSION);
-               return -ENOEXEC;
+               ret = -ENOEXEC;
+               goto err;
        }
        
        /* Don't allow old format executables to use shared libraries */
        if (rev == OLD_FLAT_VERSION && id != 0) {
                printk("BINFMT_FLAT: shared libraries are not available before rev 0x%x\n",
                                (int) FLAT_VERSION);
-               return -ENOEXEC;
+               ret = -ENOEXEC;
+               goto err;
        }
 
        /*
@@ -478,7 +484,8 @@ static int load_flat_file(struct linux_binprm * bprm,
 #ifndef CONFIG_BINFMT_ZFLAT
        if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
                printk("Support for ZFLAT executables is not enabled.\n");
-               return -ENOEXEC;
+               ret = -ENOEXEC;
+               goto err;
        }
 #endif
 
@@ -490,14 +497,27 @@ static int load_flat_file(struct linux_binprm * bprm,
        rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
        if (rlim >= RLIM_INFINITY)
                rlim = ~0;
-       if (data_len + bss_len > rlim)
-               return -ENOMEM;
+       if (data_len + bss_len > rlim) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* check file descriptor */
+       exec_fileno = get_unused_fd();
+       if (exec_fileno < 0) {
+               ret = -EMFILE;
+               goto err;
+       }
+       get_file(bprm->file);
+       fd_install(exec_fileno, bprm->file);
 
        /* Flush all traces of the currently running executable */
        if (id == 0) {
                result = flush_old_exec(bprm);
-               if (result)
-                       return result;
+               if (result) {
+                       ret = result;
+                       goto err_close;
+               }
 
                /* OK, This is the point of no return */
                set_personality(PER_LINUX);
@@ -527,7 +547,8 @@ static int load_flat_file(struct linux_binprm * bprm,
                        if (!textpos)
                                textpos = (unsigned long) -ENOMEM;
                        printk("Unable to mmap process text, errno %d\n", (int)-textpos);
-                       return(textpos);
+                       ret = textpos;
+                       goto err_close;
                }
 
                down_write(&current->mm->mmap_sem);
@@ -542,7 +563,8 @@ static int load_flat_file(struct linux_binprm * bprm,
                        printk("Unable to allocate RAM for process data, errno %d\n",
                                        (int)-datapos);
                        do_munmap(current->mm, textpos, text_len);
-                       return realdatastart;
+                       ret = realdatastart;
+                       goto err_close;
                }
                datapos = realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long);
 
@@ -564,7 +586,8 @@ static int load_flat_file(struct linux_binprm * bprm,
                        printk("Unable to read data+bss, errno %d\n", (int)-result);
                        do_munmap(current->mm, textpos, text_len);
                        do_munmap(current->mm, realdatastart, data_len + extra);
-                       return result;
+                       ret = result;
+                       goto err_close;
                }
 
                reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len));
@@ -582,7 +605,8 @@ static int load_flat_file(struct linux_binprm * bprm,
                                textpos = (unsigned long) -ENOMEM;
                        printk("Unable to allocate RAM for process text/data, errno %d\n",
                                        (int)-textpos);
-                       return(textpos);
+                       ret = textpos;
+                       goto err_close;
                }
 
                realdatastart = textpos + ntohl(hdr->data_start);
@@ -627,7 +651,8 @@ static int load_flat_file(struct linux_binprm * bprm,
                        printk("Unable to read code+data+bss, errno %d\n",(int)-result);
                        do_munmap(current->mm, textpos, text_len + data_len + extra +
                                MAX_SHARED_LIBS * sizeof(unsigned long));
-                       return result;
+                       ret = result;
+                       goto err_close;
                }
        }
 
@@ -690,8 +715,10 @@ static int load_flat_file(struct linux_binprm * bprm,
                        unsigned long addr;
                        if (*rp) {
                                addr = calc_reloc(*rp, libinfo, id, 0);
-                               if (addr == RELOC_FAILED)
-                                       return -ENOEXEC;
+                               if (addr == RELOC_FAILED) {
+                                       ret = -ENOEXEC;
+                                       goto err_close;
+                               }
                                *rp = addr;
                        }
                }
@@ -718,8 +745,10 @@ static int load_flat_file(struct linux_binprm * bprm,
                        relval = ntohl(reloc[i]);
                        addr = flat_get_relocate_addr(relval);
                        rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1);
-                       if (rp == (unsigned long *)RELOC_FAILED)
-                               return -ENOEXEC;
+                       if (rp == (unsigned long *)RELOC_FAILED) {
+                               ret = -ENOEXEC;
+                               goto err_close;
+                       }
 
                        /* Get the pointer's value.  */
                        addr = flat_get_addr_from_rp(rp, relval, flags);
@@ -731,8 +760,10 @@ static int load_flat_file(struct linux_binprm * bprm,
                                if ((flags & FLAT_FLAG_GOTPIC) == 0)
                                        addr = ntohl(addr);
                                addr = calc_reloc(addr, libinfo, id, 0);
-                               if (addr == RELOC_FAILED)
-                                       return -ENOEXEC;
+                               if (addr == RELOC_FAILED) {
+                                       ret = -ENOEXEC;
+                                       goto err_close;
+                               }
 
                                /* Write back the relocated pointer.  */
                                flat_put_addr_at_rp(rp, addr, relval);
@@ -752,6 +783,10 @@ static int load_flat_file(struct linux_binprm * bprm,
                        stack_len);
 
        return 0;
+err_close:
+       sys_close(exec_fileno);
+err:
+       return ret;
 }
 
 
index 0a8c59cb68f527fd98152d12a10ef1eb2e7f049c..73e664c01d30075064cc14b533d9d0d72b1d871f 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -636,12 +636,10 @@ static struct bio *__bio_map_user_iov(request_queue_t *q,
                return ERR_PTR(-ENOMEM);
 
        ret = -ENOMEM;
-       pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
+       pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
        if (!pages)
                goto out;
 
-       memset(pages, 0, nr_pages * sizeof(struct page *));
-
        for (i = 0; i < iov_count; i++) {
                unsigned long uaddr = (unsigned long)iov[i].iov_base;
                unsigned long len = iov[i].iov_len;
@@ -1186,12 +1184,11 @@ void bioset_free(struct bio_set *bs)
 
 struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
 {
-       struct bio_set *bs = kmalloc(sizeof(*bs), GFP_KERNEL);
+       struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
 
        if (!bs)
                return NULL;
 
-       memset(bs, 0, sizeof(*bs));
        bs->bio_pool = mempool_create(bio_pool_size, mempool_alloc_slab,
                        mempool_free_slab, bio_slab);
 
index 6d77ce9f54e52031ef23d50643bcce772ed20c65..3b3ab5281920ca00954ad38bbc2f8911fa4d18cf 100644 (file)
@@ -160,12 +160,7 @@ int sync_blockdev(struct block_device *bdev)
 }
 EXPORT_SYMBOL(sync_blockdev);
 
-/*
- * Write out and wait upon all dirty data associated with this
- * superblock.  Filesystem data as well as the underlying block
- * device.  Takes the superblock lock.
- */
-int fsync_super(struct super_block *sb)
+static void __fsync_super(struct super_block *sb)
 {
        sync_inodes_sb(sb, 0);
        DQUOT_SYNC(sb);
@@ -177,7 +172,16 @@ int fsync_super(struct super_block *sb)
                sb->s_op->sync_fs(sb, 1);
        sync_blockdev(sb->s_bdev);
        sync_inodes_sb(sb, 1);
+}
 
+/*
+ * Write out and wait upon all dirty data associated with this
+ * superblock.  Filesystem data as well as the underlying block
+ * device.  Takes the superblock lock.
+ */
+int fsync_super(struct super_block *sb)
+{
+       __fsync_super(sb);
        return sync_blockdev(sb->s_bdev);
 }
 
@@ -216,19 +220,7 @@ struct super_block *freeze_bdev(struct block_device *bdev)
                sb->s_frozen = SB_FREEZE_WRITE;
                smp_wmb();
 
-               sync_inodes_sb(sb, 0);
-               DQUOT_SYNC(sb);
-
-               lock_super(sb);
-               if (sb->s_dirt && sb->s_op->write_super)
-                       sb->s_op->write_super(sb);
-               unlock_super(sb);
-
-               if (sb->s_op->sync_fs)
-                       sb->s_op->sync_fs(sb, 1);
-
-               sync_blockdev(sb->s_bdev);
-               sync_inodes_sb(sb, 1);
+               __fsync_super(sb);
 
                sb->s_frozen = SB_FREEZE_TRANS;
                smp_wmb();
index 5c36345c9bf78376b6996604d98aba2679d6ed09..8c6eb04d31e2ab9033a067fc42393d5fa8c38a60 100644 (file)
@@ -146,12 +146,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
        int ret = 0;
        int i;
 
-       cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
+       cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
        if (cd == NULL)
                return ERR_PTR(-ENOMEM);
 
-       memset(cd, 0, sizeof(struct char_device_struct));
-
        mutex_lock(&chrdevs_lock);
 
        /* temporary */
@@ -466,9 +464,8 @@ static struct kobj_type ktype_cdev_dynamic = {
 
 struct cdev *cdev_alloc(void)
 {
-       struct cdev *p = kmalloc(sizeof(struct cdev), GFP_KERNEL);
+       struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
        if (p) {
-               memset(p, 0, sizeof(struct cdev));
                p->kobj.ktype = &ktype_cdev_dynamic;
                INIT_LIST_HEAD(&p->list);
                kobject_init(&p->kobj);
index 2a88477330fcbca9c71a8613981d205c7d8b9021..ef5a0771592d1a5d30d2cb9eb53799ed2c862520 100644 (file)
@@ -1476,10 +1476,9 @@ int compat_do_execve(char * filename,
        int i;
 
        retval = -ENOMEM;
-       bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
+       bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
        if (!bprm)
                goto out_ret;
-       memset(bprm, 0, sizeof(*bprm));
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
@@ -2170,9 +2169,12 @@ asmlinkage long compat_sys_nfsservctl(int cmd, struct compat_nfsctl_arg __user *
 
        default:
                err = -EINVAL;
-               goto done;
+               break;
        }
 
+       if (err)
+               goto done;
+
        oldfs = get_fs();
        set_fs(KERNEL_DS);
        /* The __user pointer casts are valid because of the set_fs() */
index 653f64ce98e2e8d482b23af9ece78f6f62352d40..939584648504e6552be95e13a52b46e0d27592ea 100644 (file)
@@ -325,10 +325,13 @@ static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
 
 struct dentry * d_find_alias(struct inode *inode)
 {
-       struct dentry *de;
-       spin_lock(&dcache_lock);
-       de = __d_find_alias(inode, 0);
-       spin_unlock(&dcache_lock);
+       struct dentry *de = NULL;
+
+       if (!list_empty(&inode->i_dentry)) {
+               spin_lock(&dcache_lock);
+               de = __d_find_alias(inode, 0);
+               spin_unlock(&dcache_lock);
+       }
        return de;
 }
 
@@ -486,6 +489,7 @@ repeat:
                        continue;
                }
                prune_one_dentry(dentry);
+               cond_resched_lock(&dcache_lock);
                goto repeat;
        }
        spin_unlock(&dcache_lock);
@@ -799,6 +803,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
        if (inode)
                list_add(&entry->d_alias, &inode->i_dentry);
        entry->d_inode = inode;
+       fsnotify_d_instantiate(entry, inode);
        spin_unlock(&dcache_lock);
        security_d_instantiate(entry, inode);
 }
@@ -850,6 +855,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
        list_add(&entry->d_alias, &inode->i_dentry);
 do_negative:
        entry->d_inode = inode;
+       fsnotify_d_instantiate(entry, inode);
        spin_unlock(&dcache_lock);
        security_d_instantiate(entry, inode);
        return NULL;
@@ -980,6 +986,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
                new = __d_find_alias(inode, 1);
                if (new) {
                        BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
+                       fsnotify_d_instantiate(new, inode);
                        spin_unlock(&dcache_lock);
                        security_d_instantiate(new, inode);
                        d_rehash(dentry);
@@ -989,6 +996,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
                        /* d_instantiate takes dcache_lock, so we do it by hand */
                        list_add(&dentry->d_alias, &inode->i_dentry);
                        dentry->d_inode = inode;
+                       fsnotify_d_instantiate(dentry, inode);
                        spin_unlock(&dcache_lock);
                        security_d_instantiate(dentry, inode);
                        d_rehash(dentry);
@@ -1173,6 +1181,9 @@ void d_delete(struct dentry * dentry)
        spin_lock(&dentry->d_lock);
        isdir = S_ISDIR(dentry->d_inode->i_mode);
        if (atomic_read(&dentry->d_count) == 1) {
+               /* remove this and other inotify debug checks after 2.6.18 */
+               dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
+
                dentry_iput(dentry);
                fsnotify_nameremove(dentry, isdir);
                return;
@@ -1339,6 +1350,7 @@ already_unhashed:
 
        list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
        spin_unlock(&target->d_lock);
+       fsnotify_d_move(dentry);
        spin_unlock(&dentry->d_lock);
        write_sequnlock(&rename_lock);
        spin_unlock(&dcache_lock);
index 27f3e787facaff34b29f28ed6830148a843ffbdb..235ed8d1f11e3b41cb332713108ca53ca063245a 100644 (file)
@@ -129,6 +129,7 @@ struct dio {
        /* AIO related stuff */
        struct kiocb *iocb;             /* kiocb */
        int is_async;                   /* is IO async ? */
+       int io_error;                   /* IO error in completion path */
        ssize_t result;                 /* IO result */
 };
 
@@ -250,6 +251,10 @@ static void finished_one_bio(struct dio *dio)
                            ((offset + transferred) > dio->i_size))
                                transferred = dio->i_size - offset;
 
+                       /* check for error in completion path */
+                       if (dio->io_error)
+                               transferred = dio->io_error;
+
                        dio_complete(dio, offset, transferred);
 
                        /* Complete AIO later if falling back to buffered i/o */
@@ -406,7 +411,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
        int page_no;
 
        if (!uptodate)
-               dio->result = -EIO;
+               dio->io_error = -EIO;
 
        if (dio->is_async && dio->rw == READ) {
                bio_check_pages_dirty(bio);     /* transfers ownership */
@@ -971,6 +976,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        dio->next_block_for_io = -1;
 
        dio->page_errors = 0;
+       dio->io_error = 0;
        dio->result = 0;
        dio->iocb = iocb;
        dio->i_size = i_size_read(inode);
index 1c2b16fda13aa8caf87869f29d2db8eb29ac8438..a0f682cdd03e06e8802efdf320c6da9d436d31ad 100644 (file)
@@ -599,7 +599,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
        switch (op) {
        case EPOLL_CTL_ADD:
                if (!epi) {
-                       epds.events |= POLLERR | POLLHUP;
+                       epds.events |= POLLERR | POLLHUP | POLLRDHUP;
 
                        error = ep_insert(ep, &epds, tfile, fd);
                } else
@@ -613,7 +613,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
                break;
        case EPOLL_CTL_MOD:
                if (epi) {
-                       epds.events |= POLLERR | POLLHUP;
+                       epds.events |= POLLERR | POLLHUP | POLLRDHUP;
                        error = ep_modify(ep, epi, &epds);
                } else
                        error = -ENOENT;
index 0b515ac531348650a59c61c8de6b362953b7bea7..995cba3c62b86fe51f7f21688892e534ce30e087 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -127,7 +127,7 @@ asmlinkage long sys_uselib(const char __user * library)
        struct nameidata nd;
        int error;
 
-       error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ);
+       error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
        if (error)
                goto out;
 
@@ -477,7 +477,7 @@ struct file *open_exec(const char *name)
        int err;
        struct file *file;
 
-       err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ);
+       err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
        file = ERR_PTR(err);
 
        if (!err) {
@@ -1143,10 +1143,9 @@ int do_execve(char * filename,
        int i;
 
        retval = -ENOMEM;
-       bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
+       bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
        if (!bprm)
                goto out_ret;
-       memset(bprm, 0, sizeof(*bprm));
 
        file = open_exec(filename);
        retval = PTR_ERR(file);
index 268b73f5847c5b83a8bf6ae1c05d7b4cd6dd3382..7e30bae174edce379a67c212953a90c5912b1a20 100644 (file)
@@ -211,8 +211,6 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
 
        if (sbi->s_mount_opt & EXT2_MOUNT_GRPID)
                seq_puts(seq, ",grpid");
-       else
-               seq_puts(seq, ",nogrpid");
 
 #if defined(CONFIG_QUOTA)
        if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA)
index cb16b4c5d5df4110fffe112518ef32c9c2c06ef7..ce4f82b9e528d6dd6a64045144f34792611bf764 100644 (file)
@@ -7,11 +7,11 @@
  * Universite Pierre et Marie Curie (Paris VI)
  */
 
-#ifdef EXT3FS_DEBUG
-
 #include <linux/buffer_head.h>
+#include <linux/jbd.h>
+#include <linux/ext3_fs.h>
 
-#include "ext3_fs.h"
+#ifdef EXT3FS_DEBUG
 
 static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
 
index 785c7213a54f513186aa5e403a1a3066f646eb12..f3fbe2d030f4def8fae388ef49bc617bf251e913 100644 (file)
@@ -381,8 +381,8 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
                        list_move(&inode->i_list, &sb->s_dirty);
                }
                spin_unlock(&inode_lock);
-               cond_resched();
                iput(inode);
+               cond_resched();
                spin_lock(&inode_lock);
                if (wbc->nr_to_write <= 0)
                        break;
index a51c671c54cfce57c702651450269fef1b1d7c0e..85da11044adc0c1482362377aedf5f721c19bbb3 100644 (file)
@@ -91,7 +91,7 @@ DEFINE_SPINLOCK(inode_lock);
  * from its final dispose_list, the struct super_block they refer to
  * (for inode->i_sb->s_op) may already have been freed and reused.
  */
-DEFINE_MUTEX(iprune_mutex);
+static DEFINE_MUTEX(iprune_mutex);
 
 /*
  * Statistics gathering..
index 0ee39ef591c6dac600a4cb07d2741be546becc38..a61e93e1785331eb87847df058b7b1b504459250 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/ioctls.h>
 
 static atomic_t inotify_cookie;
-static atomic_t inotify_watches;
 
 static kmem_cache_t *watch_cachep;
 static kmem_cache_t *event_cachep;
@@ -380,6 +379,48 @@ static int find_inode(const char __user *dirname, struct nameidata *nd,
        return error;
 }
 
+/*
+ * inotify_inode_watched - returns nonzero if there are watches on this inode
+ * and zero otherwise.  We call this lockless, we do not care if we race.
+ */
+static inline int inotify_inode_watched(struct inode *inode)
+{
+       return !list_empty(&inode->inotify_watches);
+}
+
+/*
+ * Get child dentry flag into synch with parent inode.
+ * Flag should always be clear for negative dentrys.
+ */
+static void set_dentry_child_flags(struct inode *inode, int watched)
+{
+       struct dentry *alias;
+
+       spin_lock(&dcache_lock);
+       list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+               struct dentry *child;
+
+               list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
+                       if (!child->d_inode) {
+                               WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
+                               continue;
+                       }
+                       spin_lock(&child->d_lock);
+                       if (watched) {
+                               WARN_ON(child->d_flags &
+                                               DCACHE_INOTIFY_PARENT_WATCHED);
+                               child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
+                       } else {
+                               WARN_ON(!(child->d_flags &
+                                       DCACHE_INOTIFY_PARENT_WATCHED));
+                               child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED;
+                       }
+                       spin_unlock(&child->d_lock);
+               }
+       }
+       spin_unlock(&dcache_lock);
+}
+
 /*
  * create_watch - creates a watch on the given device.
  *
@@ -426,7 +467,6 @@ static struct inotify_watch *create_watch(struct inotify_device *dev,
        get_inotify_watch(watch);
 
        atomic_inc(&dev->user->inotify_watches);
-       atomic_inc(&inotify_watches);
 
        return watch;
 }
@@ -458,8 +498,10 @@ static void remove_watch_no_event(struct inotify_watch *watch,
        list_del(&watch->i_list);
        list_del(&watch->d_list);
 
+       if (!inotify_inode_watched(watch->inode))
+               set_dentry_child_flags(watch->inode, 0);
+
        atomic_dec(&dev->user->inotify_watches);
-       atomic_dec(&inotify_watches);
        idr_remove(&dev->idr, watch->wd);
        put_inotify_watch(watch);
 }
@@ -481,16 +523,39 @@ static void remove_watch(struct inotify_watch *watch,struct inotify_device *dev)
        remove_watch_no_event(watch, dev);
 }
 
+/* Kernel API */
+
 /*
- * inotify_inode_watched - returns nonzero if there are watches on this inode
- * and zero otherwise.  We call this lockless, we do not care if we race.
+ * inotify_d_instantiate - instantiate dcache entry for inode
  */
-static inline int inotify_inode_watched(struct inode *inode)
+void inotify_d_instantiate(struct dentry *entry, struct inode *inode)
 {
-       return !list_empty(&inode->inotify_watches);
+       struct dentry *parent;
+
+       if (!inode)
+               return;
+
+       WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
+       spin_lock(&entry->d_lock);
+       parent = entry->d_parent;
+       if (inotify_inode_watched(parent->d_inode))
+               entry->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
+       spin_unlock(&entry->d_lock);
 }
 
-/* Kernel API */
+/*
+ * inotify_d_move - dcache entry has been moved
+ */
+void inotify_d_move(struct dentry *entry)
+{
+       struct dentry *parent;
+
+       parent = entry->d_parent;
+       if (inotify_inode_watched(parent->d_inode))
+               entry->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
+       else
+               entry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
+}
 
 /**
  * inotify_inode_queue_event - queue an event to all watches on this inode
@@ -538,7 +603,7 @@ void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask,
        struct dentry *parent;
        struct inode *inode;
 
-       if (!atomic_read (&inotify_watches))
+       if (!(dentry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED))
                return;
 
        spin_lock(&dentry->d_lock);
@@ -993,6 +1058,9 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
                goto out;
        }
 
+       if (!inotify_inode_watched(inode))
+               set_dentry_child_flags(inode, 1);
+
        /* Add the watch to the device's and the inode's list */
        list_add(&watch->d_list, &dev->watches);
        list_add(&watch->i_list, &inode->inotify_watches);
@@ -1065,7 +1133,6 @@ static int __init inotify_setup(void)
        inotify_max_user_watches = 8192;
 
        atomic_set(&inotify_cookie, 0);
-       atomic_set(&inotify_watches, 0);
 
        watch_cachep = kmem_cache_create("inotify_watch_cache",
                                         sizeof(struct inotify_watch),
index 95a628d8cac87be34e2e88054ef1580ce4f2cf27..7f96b5cb67816109e38a51b79a6ee80364e48c5d 100644 (file)
 #include <linux/mm.h>
 #include <linux/suspend.h>
 #include <linux/pagemap.h>
+#include <linux/kthread.h>
+#include <linux/proc_fs.h>
+
 #include <asm/uaccess.h>
 #include <asm/page.h>
-#include <linux/proc_fs.h>
 
 EXPORT_SYMBOL(journal_start);
 EXPORT_SYMBOL(journal_restart);
@@ -111,18 +113,15 @@ static void commit_timeout(unsigned long __data)
 
 static int kjournald(void *arg)
 {
-       journal_t *journal = (journal_t *) arg;
+       journal_t *journal = arg;
        transaction_t *transaction;
-       struct timer_list timer;
 
-       daemonize("kjournald");
-
-       /* Set up an interval timer which can be used to trigger a
-           commit wakeup after the commit interval expires */
-       init_timer(&timer);
-       timer.data = (unsigned long) current;
-       timer.function = commit_timeout;
-       journal->j_commit_timer = &timer;
+       /*
+        * Set up an interval timer which can be used to trigger a commit wakeup
+        * after the commit interval expires
+        */
+       setup_timer(&journal->j_commit_timer, commit_timeout,
+                       (unsigned long)current);
 
        /* Record that the journal thread is running */
        journal->j_task = current;
@@ -146,7 +145,7 @@ loop:
        if (journal->j_commit_sequence != journal->j_commit_request) {
                jbd_debug(1, "OK, requests differ\n");
                spin_unlock(&journal->j_state_lock);
-               del_timer_sync(journal->j_commit_timer);
+               del_timer_sync(&journal->j_commit_timer);
                journal_commit_transaction(journal);
                spin_lock(&journal->j_state_lock);
                goto loop;
@@ -203,7 +202,7 @@ loop:
 
 end_loop:
        spin_unlock(&journal->j_state_lock);
-       del_timer_sync(journal->j_commit_timer);
+       del_timer_sync(&journal->j_commit_timer);
        journal->j_task = NULL;
        wake_up(&journal->j_wait_done_commit);
        jbd_debug(1, "Journal thread exiting.\n");
@@ -212,7 +211,7 @@ end_loop:
 
 static void journal_start_thread(journal_t *journal)
 {
-       kernel_thread(kjournald, journal, CLONE_VM|CLONE_FS|CLONE_FILES);
+       kthread_run(kjournald, journal, "kjournald");
        wait_event(journal->j_wait_done_commit, journal->j_task != 0);
 }
 
index 5fc40888f4cf924ef273fc0b1cbfa9db2f1d3cc6..ada31fa272e37ef9277d493ca006fbb81060b918 100644 (file)
@@ -53,8 +53,8 @@ get_transaction(journal_t *journal, transaction_t *transaction)
        spin_lock_init(&transaction->t_handle_lock);
 
        /* Set up the commit timer for the new transaction. */
-       journal->j_commit_timer->expires = transaction->t_expires;
-       add_timer(journal->j_commit_timer);
+       journal->j_commit_timer.expires = transaction->t_expires;
+       add_timer(&journal->j_commit_timer);
 
        J_ASSERT(journal->j_running_transaction == NULL);
        journal->j_running_transaction = transaction;
index dc6a4e4abcdc8645e41a3a96ef9cb4695be33798..4a6abc49418ef9917106d3ed6077be25154e57e4 100644 (file)
@@ -56,7 +56,7 @@ void minix_free_block(struct inode * inode, int block)
        unsigned int bit,zone;
 
        if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
-               printk("trying to free block not in datazone\n");
+               printk("Trying to free block not in datazone\n");
                return;
        }
        zone = block - sbi->s_firstdatazone + 1;
@@ -124,7 +124,7 @@ minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
                 ino / MINIX_INODES_PER_BLOCK;
        *bh = sb_bread(sb, block);
        if (!*bh) {
-               printk("unable to read i-node block\n");
+               printk("Unable to read inode block\n");
                return NULL;
        }
        p = (void *)(*bh)->b_data;
@@ -149,7 +149,7 @@ minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
                 ino / MINIX2_INODES_PER_BLOCK;
        *bh = sb_bread(sb, block);
        if (!*bh) {
-               printk("unable to read i-node block\n");
+               printk("Unable to read inode block\n");
                return NULL;
        }
        p = (void *)(*bh)->b_data;
@@ -204,7 +204,7 @@ void minix_free_inode(struct inode * inode)
        bh = sbi->s_imap[ino >> 13];
        lock_kernel();
        if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
-               printk("minix_free_inode: bit %lu already cleared.\n", ino);
+               printk("minix_free_inode: bit %lu already cleared\n", ino);
        unlock_kernel();
        mark_buffer_dirty(bh);
  out:
@@ -238,7 +238,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
                return NULL;
        }
        if (minix_test_and_set_bit(j,bh->b_data)) {     /* shouldn't happen */
-               printk("new_inode: bit already set");
+               printk("new_inode: bit already set\n");
                unlock_kernel();
                iput(inode);
                return NULL;
index d9ffc43fee593c5f3eb553544d57970395588625..2dcccf1d1b7f7d2b72110e2d2be6b3a2f911b0b8 100644 (file)
@@ -127,11 +127,11 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
                mark_buffer_dirty(sbi->s_sbh);
 
                if (!(sbi->s_mount_state & MINIX_VALID_FS))
-                       printk ("MINIX-fs warning: remounting unchecked fs, "
-                               "running fsck is recommended.\n");
+                       printk("MINIX-fs warning: remounting unchecked fs, "
+                               "running fsck is recommended\n");
                else if ((sbi->s_mount_state & MINIX_ERROR_FS))
-                       printk ("MINIX-fs warning: remounting fs with errors, "
-                               "running fsck is recommended.\n");
+                       printk("MINIX-fs warning: remounting fs with errors, "
+                               "running fsck is recommended\n");
        }
        return 0;
 }
@@ -245,11 +245,11 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
                mark_buffer_dirty(bh);
        }
        if (!(sbi->s_mount_state & MINIX_VALID_FS))
-               printk ("MINIX-fs: mounting unchecked file system, "
-                       "running fsck is recommended.\n");
+               printk("MINIX-fs: mounting unchecked file system, "
+                       "running fsck is recommended\n");
        else if (sbi->s_mount_state & MINIX_ERROR_FS)
-               printk ("MINIX-fs: mounting file system with errors, "
-                       "running fsck is recommended.\n");
+               printk("MINIX-fs: mounting file system with errors, "
+                       "running fsck is recommended\n");
        return 0;
 
 out_iput:
@@ -273,19 +273,19 @@ out_no_bitmap:
 
 out_no_map:
        if (!silent)
-               printk ("MINIX-fs: can't allocate map\n");
+               printk("MINIX-fs: can't allocate map\n");
        goto out_release;
 
 out_no_fs:
        if (!silent)
-               printk("VFS: Can't find a Minix or Minix V2 filesystem on device "
-                      "%s.\n", s->s_id);
+               printk("VFS: Can't find a Minix or Minix V2 filesystem "
+                       "on device %s\n", s->s_id);
     out_release:
        brelse(bh);
        goto out;
 
 out_bad_hblock:
-       printk("MINIX-fs: blocksize too small for device.\n");
+       printk("MINIX-fs: blocksize too small for device\n");
        goto out;
 
 out_bad_sb:
@@ -524,7 +524,7 @@ int minix_sync_inode(struct inode * inode)
                sync_dirty_buffer(bh);
                if (buffer_req(bh) && !buffer_uptodate(bh))
                {
-                       printk ("IO error syncing minix inode [%s:%08lx]\n",
+                       printk("IO error syncing minix inode [%s:%08lx]\n",
                                inode->i_sb->s_id, inode->i_ino);
                        err = -1;
                }
index ba06aef4aca1311f250caf9bd7aec11a066e4900..656b1347a25bee35577d0d2cb73a190f9f3adac2 100644 (file)
@@ -25,9 +25,9 @@ static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
        int n = 0;
 
        if (block < 0) {
-               printk("minix_bmap: block<0");
+               printk("minix_bmap: block<0\n");
        } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
-               printk("minix_bmap: block>big");
+               printk("minix_bmap: block>big\n");
        } else if (block < 7) {
                offsets[n++] = block;
        } else if ((block -= 7) < 512) {
index 3adc7675560f2e11615a3807b65e2fea20eca5e5..9adcdc754e0fc2da58b7496b472789d41a910445 100644 (file)
@@ -25,9 +25,9 @@ static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
        int n = 0;
 
        if (block < 0) {
-               printk("minix_bmap: block<0");
+               printk("minix_bmap: block<0\n");
        } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
-               printk("minix_bmap: block>big");
+               printk("minix_bmap: block>big\n");
        } else if (block < 7) {
                offsets[n++] = block;
        } else if ((block -= 7) < 256) {
index c72b940797fc0321fcb6043610bc50138a2325ed..712dfc77793bcb6a0bff52bc00d50248050117eb 100644 (file)
@@ -1628,6 +1628,12 @@ do_last:
                goto exit;
        }
 
+       if (IS_ERR(nd->intent.open.file)) {
+               mutex_unlock(&dir->d_inode->i_mutex);
+               error = PTR_ERR(nd->intent.open.file);
+               goto exit_dput;
+       }
+
        /* Negative dentry, just create the file */
        if (!path.dentry->d_inode) {
                if (!IS_POSIXACL(dir->d_inode))
@@ -2621,16 +2627,27 @@ int __page_symlink(struct inode *inode, const char *symname, int len,
        int err = -ENOMEM;
        char *kaddr;
 
+retry:
        page = find_or_create_page(mapping, 0, gfp_mask);
        if (!page)
                goto fail;
        err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
+       if (err == AOP_TRUNCATED_PAGE) {
+               page_cache_release(page);
+               goto retry;
+       }
        if (err)
                goto fail_map;
        kaddr = kmap_atomic(page, KM_USER0);
        memcpy(kaddr, symname, len-1);
        kunmap_atomic(kaddr, KM_USER0);
-       mapping->a_ops->commit_write(NULL, page, 0, len-1);
+       err = mapping->a_ops->commit_write(NULL, page, 0, len-1);
+       if (err == AOP_TRUNCATED_PAGE) {
+               page_cache_release(page);
+               goto retry;
+       }
+       if (err)
+               goto fail_map;
        /*
         * Notice that we are _not_ going to block here - end of page is
         * unmapped, so this will only try to map the rest of page, see
@@ -2640,7 +2657,8 @@ int __page_symlink(struct inode *inode, const char *symname, int len,
         */
        if (!PageUptodate(page)) {
                err = mapping->a_ops->readpage(NULL, page);
-               wait_on_page_locked(page);
+               if (err != AOP_TRUNCATED_PAGE)
+                       wait_on_page_locked(page);
        } else {
                unlock_page(page);
        }
index 1091dadd6c381e6ff0b7e69adad80734d9502792..7d02d19bd0a28281a108353883902fae745e1f10 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -890,6 +890,10 @@ EXPORT_SYMBOL(filp_open);
  * a fully instantiated struct file to the caller.
  * This function is meant to be called from within a filesystem's
  * lookup method.
+ * Beware of calling it for non-regular files! Those ->open methods might block
+ * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
+ * leading to a deadlock, as nobody can open that fifo anymore, because
+ * another process to open fifo will block on locked parent when doing lookup).
  * Note that in case of error, nd->intent.open.file is destroyed, but the
  * path information remains valid.
  * If the open callback is set to NULL, then the standard f_op->open()
index 8aada8e426f44f12095b59810c5f270bc128f014..d976866a115b8e0b975e3cea3c7ccdecb74a6d12 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -662,10 +662,9 @@ struct inode* pipe_new(struct inode* inode)
 {
        struct pipe_inode_info *info;
 
-       info = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
+       info = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
        if (!info)
                goto fail_page;
-       memset(info, 0, sizeof(*info));
        inode->i_pipe = info;
 
        init_waitqueue_head(PIPE_WAIT(*inode));
index 826c131994c38008226a0bb1c3fa668c11d13403..1e9ea37d457e246fdc10c1dbfe63e14d443b759d 100644 (file)
@@ -485,6 +485,40 @@ static struct file_operations proc_slabinfo_operations = {
        .llseek         = seq_lseek,
        .release        = seq_release,
 };
+
+#ifdef CONFIG_DEBUG_SLAB_LEAK
+extern struct seq_operations slabstats_op;
+static int slabstats_open(struct inode *inode, struct file *file)
+{
+       unsigned long *n = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       int ret = -ENOMEM;
+       if (n) {
+               ret = seq_open(file, &slabstats_op);
+               if (!ret) {
+                       struct seq_file *m = file->private_data;
+                       *n = PAGE_SIZE / (2 * sizeof(unsigned long));
+                       m->private = n;
+                       n = NULL;
+               }
+               kfree(n);
+       }
+       return ret;
+}
+
+static int slabstats_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *m = file->private_data;
+       kfree(m->private);
+       return seq_release(inode, file);
+}
+
+static struct file_operations proc_slabstats_operations = {
+       .open           = slabstats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = slabstats_release,
+};
+#endif
 #endif
 
 static int show_stat(struct seq_file *p, void *v)
@@ -744,6 +778,9 @@ void __init proc_misc_init(void)
        create_seq_entry("interrupts", 0, &proc_interrupts_operations);
 #ifdef CONFIG_SLAB
        create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
+#ifdef CONFIG_DEBUG_SLAB_LEAK
+       create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations);
+#endif
 #endif
        create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
        create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
index 3f7a1a62165f626e984de4849ce053cc8a824f65..34b1bf259efd239d5380282b689258285711fc5e 100644 (file)
@@ -470,7 +470,7 @@ static ssize_t do_readv_writev(int type, struct file *file,
         * verify all the pointers
         */
        ret = -EINVAL;
-       if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
+       if (nr_segs > UIO_MAXIOV)
                goto out;
        if (!file->f_op)
                goto out;
index be12879bb179ac881134a1c7ed9dc0d577d7b061..d0c1e865963eac20acc606cc8f26089f20ad2ac1 100644 (file)
@@ -1532,7 +1532,7 @@ static ssize_t reiserfs_file_write(struct file *file,     /* the file we are going t
                buf += write_bytes;
                *ppos = pos += write_bytes;
                count -= write_bytes;
-               balance_dirty_pages_ratelimited(inode->i_mapping);
+               balance_dirty_pages_ratelimited_nr(inode->i_mapping, num_pages);
        }
 
        /* this is only true on error */
@@ -1546,10 +1546,10 @@ static ssize_t reiserfs_file_write(struct file *file,   /* the file we are going t
                }
        }
 
-       if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
-               res =
-                   generic_osync_inode(inode, file->f_mapping,
-                                       OSYNC_METADATA | OSYNC_DATA);
+       if (likely(res >= 0) &&
+           (unlikely((file->f_flags & O_SYNC) || IS_SYNC(inode))))
+               res = generic_osync_inode(inode, file->f_mapping,
+                                         OSYNC_METADATA | OSYNC_DATA);
 
        mutex_unlock(&inode->i_mutex);
        reiserfs_async_progress_wait(inode->i_sb);
index aa22588019ecd56fd32b0e80ac7f5c58f9671899..5600d3d60cf7d9f467ff5fc0f0046cc0adb8070f 100644 (file)
@@ -191,9 +191,7 @@ static void create_virtual_node(struct tree_balance *tb, int h)
                                               "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c",
                                               key, vn->vn_affected_item_num,
                                               vn->vn_mode, M_DELETE);
-                       } else
-                               /* we can delete directory item, that has only one directory entry in it */
-                               ;
+                       }
                }
 #endif
 
index e237cd668e5bec874a8227d7efbdce195f69f9e0..7a88adbceef6ece45562579d2c24cdb6b196d33e 100644 (file)
@@ -275,7 +275,7 @@ static void indirect_print_item(struct item_head *ih, char *item)
        int j;
        __le32 *unp;
        __u32 prev = INT_MAX;
-       int num;
+       int num = 0;
 
        unp = (__le32 *) item;
 
index 5a9d2722fa0adf4d507072e7c5c3db65dd5aff75..1b73529b8099bbb7bc758869c09e8ff27d802ce0 100644 (file)
@@ -2227,6 +2227,9 @@ static int journal_read_transaction(struct super_block *p_s_sb,
        journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
        journal->j_last_flush_trans_id = trans_id;
        journal->j_trans_id = trans_id + 1;
+       /* check for trans_id overflow */
+       if (journal->j_trans_id == 0)
+               journal->j_trans_id = 10;
        brelse(c_bh);
        brelse(d_bh);
        kfree(log_blocks);
@@ -2450,6 +2453,9 @@ static int journal_read(struct super_block *p_s_sb)
                journal->j_start = le32_to_cpu(jh->j_first_unflushed_offset);
                journal->j_trans_id =
                    le32_to_cpu(jh->j_last_flush_trans_id) + 1;
+               /* check for trans_id overflow */
+               if (journal->j_trans_id == 0)
+                       journal->j_trans_id = 10;
                journal->j_last_flush_trans_id =
                    le32_to_cpu(jh->j_last_flush_trans_id);
                journal->j_mount_id = le32_to_cpu(jh->j_mount_id) + 1;
@@ -3873,8 +3879,8 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        int cur_write_start = 0;        /* start index of current log write */
        int old_start;
        int i;
-       int flush = flags & FLUSH_ALL;
-       int wait_on_commit = flags & WAIT;
+       int flush;
+       int wait_on_commit;
        struct reiserfs_journal_list *jl, *temp_jl;
        struct list_head *entry, *safe;
        unsigned long jindex;
@@ -3884,6 +3890,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        BUG_ON(th->t_refcount > 1);
        BUG_ON(!th->t_trans_id);
 
+       /* protect flush_older_commits from doing mistakes if the
+           transaction ID counter gets overflowed.  */
+       if (th->t_trans_id == ~0UL)
+               flags |= FLUSH_ALL | COMMIT_NOW | WAIT;
+       flush = flags & FLUSH_ALL;
+       wait_on_commit = flags & WAIT;
+
        put_fs_excl();
        current->journal_info = th->t_handle_save;
        reiserfs_check_lock_depth(p_s_sb, "journal end");
@@ -4105,7 +4118,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
        journal->j_first = NULL;
        journal->j_len = 0;
        journal->j_trans_start_time = 0;
-       journal->j_trans_id++;
+       /* check for trans_id overflow */
+       if (++journal->j_trans_id == 0)
+               journal->j_trans_id = 10;
        journal->j_current_jl->j_trans_id = journal->j_trans_id;
        journal->j_must_wait = 0;
        journal->j_len_alloc = 0;
index e2d08d7bcffcf3ca434b42f5ff701c39e376c87a..d2b25e1ba6e9739c5bd49b58945d50a7956fb74d 100644 (file)
@@ -981,6 +981,8 @@ static inline int prepare_for_direntry_item(struct path *path,
        return M_CUT;
 }
 
+#define JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD (2 * JOURNAL_PER_BALANCE_CNT + 1)
+
 /*  If the path points to a directory or direct item, calculate mode and the size cut, for balance.
     If the path points to an indirect item, remove some number of its unformatted nodes.
     In case of file truncate calculate whether this item must be deleted/truncated or last
@@ -1020,148 +1022,79 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st
 
        /* Case of an indirect item. */
        {
-               int n_unfm_number,      /* Number of the item unformatted nodes. */
-                n_counter, n_blk_size;
-               __le32 *p_n_unfm_pointer;       /* Pointer to the unformatted node number. */
-               __u32 tmp;
-               struct item_head s_ih;  /* Item header. */
-               char c_mode;    /* Returned mode of the balance. */
-               int need_research;
-
-               n_blk_size = p_s_sb->s_blocksize;
-
-               /* Search for the needed object indirect item until there are no unformatted nodes to be removed. */
-               do {
-                       need_research = 0;
-                       p_s_bh = PATH_PLAST_BUFFER(p_s_path);
-                       /* Copy indirect item header to a temp variable. */
-                       copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
-                       /* Calculate number of unformatted nodes in this item. */
-                       n_unfm_number = I_UNFM_NUM(&s_ih);
-
-                       RFALSE(!is_indirect_le_ih(&s_ih) || !n_unfm_number ||
-                              pos_in_item(p_s_path) + 1 != n_unfm_number,
-                              "PAP-5240: invalid item %h "
-                              "n_unfm_number = %d *p_n_pos_in_item = %d",
-                              &s_ih, n_unfm_number, pos_in_item(p_s_path));
-
-                       /* Calculate balance mode and position in the item to remove unformatted nodes. */
-                       if (n_new_file_length == max_reiserfs_offset(inode)) {  /* Case of delete. */
-                               pos_in_item(p_s_path) = 0;
-                               *p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
-                               c_mode = M_DELETE;
-                       } else {        /* Case of truncate. */
-                               if (n_new_file_length < le_ih_k_offset(&s_ih)) {
-                                       pos_in_item(p_s_path) = 0;
-                                       *p_n_cut_size =
-                                           -(IH_SIZE + ih_item_len(&s_ih));
-                                       c_mode = M_DELETE;      /* Delete this item. */
-                               } else {
-                                       /* indirect item must be truncated starting from *p_n_pos_in_item-th position */
-                                       pos_in_item(p_s_path) =
-                                           (n_new_file_length + n_blk_size -
-                                            le_ih_k_offset(&s_ih)) >> p_s_sb->
-                                           s_blocksize_bits;
-
-                                       RFALSE(pos_in_item(p_s_path) >
-                                              n_unfm_number,
-                                              "PAP-5250: invalid position in the item");
-
-                                       /* Either convert last unformatted node of indirect item to direct item or increase
-                                          its free space.  */
-                                       if (pos_in_item(p_s_path) ==
-                                           n_unfm_number) {
-                                               *p_n_cut_size = 0;      /* Nothing to cut. */
-                                               return M_CONVERT;       /* Maybe convert last unformatted node to the direct item. */
-                                       }
-                                       /* Calculate size to cut. */
-                                       *p_n_cut_size =
-                                           -(ih_item_len(&s_ih) -
-                                             pos_in_item(p_s_path) *
-                                             UNFM_P_SIZE);
-
-                                       c_mode = M_CUT; /* Cut from this indirect item. */
-                               }
-                       }
+           int blk_size = p_s_sb->s_blocksize;
+           struct item_head s_ih;
+           int need_re_search;
+           int delete = 0;
+           int result = M_CUT;
+           int pos = 0;
+
+           if ( n_new_file_length == max_reiserfs_offset (inode) ) {
+               /* prepare_for_delete_or_cut() is called by
+                * reiserfs_delete_item() */
+               n_new_file_length = 0;
+               delete = 1;
+           }
+
+           do {
+               need_re_search = 0;
+               *p_n_cut_size = 0;
+               p_s_bh = PATH_PLAST_BUFFER(p_s_path);
+               copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+               pos = I_UNFM_NUM(&s_ih);
 
-                       RFALSE(n_unfm_number <= pos_in_item(p_s_path),
-                              "PAP-5260: invalid position in the indirect item");
-
-                       /* pointers to be cut */
-                       n_unfm_number -= pos_in_item(p_s_path);
-                       /* Set pointer to the last unformatted node pointer that is to be cut. */
-                       p_n_unfm_pointer =
-                           (__le32 *) B_I_PITEM(p_s_bh,
-                                                &s_ih) + I_UNFM_NUM(&s_ih) -
-                           1 - *p_n_removed;
-
-                       /* We go through the unformatted nodes pointers of the indirect
-                          item and look for the unformatted nodes in the cache. If we
-                          found some of them we free it, zero corresponding indirect item
-                          entry and log buffer containing that indirect item. For this we
-                          need to prepare last path element for logging. If some
-                          unformatted node has b_count > 1 we must not free this
-                          unformatted node since it is in use. */
-                       reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1);
-                       // note: path could be changed, first line in for loop takes care
-                       // of it
+               while (le_ih_k_offset (&s_ih) + (pos - 1) * blk_size > n_new_file_length) {
+                   __u32 *unfm, block;
 
-                       for (n_counter = *p_n_removed;
-                            n_counter < n_unfm_number;
-                            n_counter++, p_n_unfm_pointer--) {
+                   /* Each unformatted block deletion may involve one additional
+                    * bitmap block into the transaction, thereby the initial
+                    * journal space reservation might not be enough. */
+                   if (!delete && (*p_n_cut_size) != 0 &&
+                       reiserfs_transaction_free_space(th) < JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) {
+                       break;
+                   }
 
-                               cond_resched();
-                               if (item_moved(&s_ih, p_s_path)) {
-                                       need_research = 1;
-                                       break;
-                               }
-                               RFALSE(p_n_unfm_pointer <
-                                      (__le32 *) B_I_PITEM(p_s_bh, &s_ih)
-                                      || p_n_unfm_pointer >
-                                      (__le32 *) B_I_PITEM(p_s_bh,
-                                                           &s_ih) +
-                                      I_UNFM_NUM(&s_ih) - 1,
-                                      "vs-5265: pointer out of range");
-
-                               /* Hole, nothing to remove. */
-                               if (!get_block_num(p_n_unfm_pointer, 0)) {
-                                       (*p_n_removed)++;
-                                       continue;
-                               }
+                   unfm = (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + pos - 1;
+                   block = get_block_num(unfm, 0);
 
-                               (*p_n_removed)++;
+                   if (block != 0) {
+                       reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1);
+                       put_block_num(unfm, 0, 0);
+                       journal_mark_dirty (th, p_s_sb, p_s_bh);
+                       reiserfs_free_block(th, inode, block, 1);
+                   }
 
-                               tmp = get_block_num(p_n_unfm_pointer, 0);
-                               put_block_num(p_n_unfm_pointer, 0, 0);
-                               journal_mark_dirty(th, p_s_sb, p_s_bh);
-                               reiserfs_free_block(th, inode, tmp, 1);
-                               if (item_moved(&s_ih, p_s_path)) {
-                                       need_research = 1;
-                                       break;
-                               }
-                       }
+                   cond_resched();
 
-                       /* a trick.  If the buffer has been logged, this
-                        ** will do nothing.  If we've broken the loop without
-                        ** logging it, it will restore the buffer
-                        **
-                        */
-                       reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
-
-                       /* This loop can be optimized. */
-               } while ((*p_n_removed < n_unfm_number || need_research) &&
-                        search_for_position_by_key(p_s_sb, p_s_item_key,
-                                                   p_s_path) ==
-                        POSITION_FOUND);
-
-               RFALSE(*p_n_removed < n_unfm_number,
-                      "PAP-5310: indirect item is not found");
-               RFALSE(item_moved(&s_ih, p_s_path),
-                      "after while, comp failed, retry");
-
-               if (c_mode == M_CUT)
-                       pos_in_item(p_s_path) *= UNFM_P_SIZE;
-               return c_mode;
+                   if (item_moved (&s_ih, p_s_path))  {
+                       need_re_search = 1;
+                       break;
+                   }
+
+                   pos --;
+                   (*p_n_removed) ++;
+                   (*p_n_cut_size) -= UNFM_P_SIZE;
+
+                   if (pos == 0) {
+                       (*p_n_cut_size) -= IH_SIZE;
+                       result = M_DELETE;
+                       break;
+                   }
+               }
+               /* a trick.  If the buffer has been logged, this will do nothing.  If
+               ** we've broken the loop without logging it, it will restore the
+               ** buffer */
+               reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
+           } while (need_re_search &&
+                    search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND);
+           pos_in_item(p_s_path) = pos * UNFM_P_SIZE;
+
+           if (*p_n_cut_size == 0) {
+               /* Nothing were cut. maybe convert last unformatted node to the
+                * direct item? */
+               result = M_CONVERT;
+           }
+           return result;
        }
 }
 
@@ -1948,7 +1881,8 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
                 ** sure the file is consistent before ending the current trans
                 ** and starting a new one
                 */
-               if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
+               if (journal_transaction_should_end(th, 0) ||
+                   reiserfs_transaction_free_space(th) <= JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) {
                        int orig_len_alloc = th->t_blocks_allocated;
                        decrement_counters_in_path(&s_search_path);
 
@@ -1962,7 +1896,7 @@ int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p
                        if (err)
                                goto out;
                        err = journal_begin(th, p_s_inode->i_sb,
-                                           JOURNAL_PER_BALANCE_CNT * 6);
+                                           JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD + JOURNAL_PER_BALANCE_CNT * 4) ;
                        if (err)
                                goto out;
                        reiserfs_update_inode_transaction(p_s_inode);
index 93e6ef9360e3128c186fc147bc7f1436d76d602e..cae2abbc0c713933a4283f9e66f215ebd3ec57db 100644 (file)
@@ -685,14 +685,14 @@ static const arg_desc_t logging_mode[] = {
         (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_WRITEBACK)},
        {"writeback", 1 << REISERFS_DATA_WRITEBACK,
         (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_LOG)},
-       {NULL, 0}
+       {.value = NULL}
 };
 
 /* possible values for -o barrier= */
 static const arg_desc_t barrier_mode[] = {
        {"none", 1 << REISERFS_BARRIER_NONE, 1 << REISERFS_BARRIER_FLUSH},
        {"flush", 1 << REISERFS_BARRIER_FLUSH, 1 << REISERFS_BARRIER_NONE},
-       {NULL, 0}
+       {.value = NULL}
 };
 
 /* possible values for "-o block-allocator=" and bits which are to be set in
@@ -890,7 +890,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options,     /* strin
                {"acl",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
                {"noacl",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
 #endif
-               {"nolog",},     /* This is unsupported */
+               {.option_name = "nolog"},
                {"replayonly",.setmask = 1 << REPLAYONLY},
                {"block-allocator",.arg_required = 'a',.values = balloc},
                {"data",.arg_required = 'd',.values = logging_mode},
@@ -908,7 +908,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options,     /* strin
                {"grpjquota",.arg_required =
                 'g' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
                {"jqfmt",.arg_required = 'f',.values = NULL},
-               {NULL,}
+               {.option_name = NULL}
        };
 
        *blocks = 0;
index ab8894c3b9e51b6d589f957b4cf2e8ead3367dfd..58c418fbca2cc3e4405b194299fcb3dfaa4dbc79 100644 (file)
@@ -182,7 +182,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
 {
        char *name, *value;
        struct posix_acl *acl, **p_acl;
-       size_t size;
+       int size;
        int retval;
        struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
 
@@ -206,7 +206,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
                return posix_acl_dup(*p_acl);
 
        size = reiserfs_xattr_get(inode, name, NULL, 0);
-       if ((int)size < 0) {
+       if (size < 0) {
                if (size == -ENODATA || size == -ENOSYS) {
                        *p_acl = ERR_PTR(-ENODATA);
                        return NULL;
index 44ed1d418b46b21de5049580fb32c851ef243d5e..fdeabc0a34f7c041db719baa85dfca8db2ccd6d1 100644 (file)
@@ -217,7 +217,7 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
        if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) {
                VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
                        inode->i_ino,
-                       (long) last_time, (long) inode->i_mtime,
+                       (long) last_time, (long) inode->i_mtime.tv_sec,
                        (long) last_sz, (long) inode->i_size);
 
                if (!S_ISDIR(inode->i_mode))
index 37554b8761829309b773e6f38b3a88e0be9ac761..8743e9bbb297e939563d5bd3ea8e7de9c2ae74ef 100644 (file)
@@ -55,11 +55,10 @@ DEFINE_SPINLOCK(sb_lock);
  */
 static struct super_block *alloc_super(void)
 {
-       struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
+       struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);
        static struct super_operations default_op;
 
        if (s) {
-               memset(s, 0, sizeof(struct super_block));
                if (security_sb_alloc(s)) {
                        kfree(s);
                        s = NULL;
index d04cff2273b681a9944f3a319af83114340341cb..81e0e8459af1159921b8b8f3f99e419b3e7869aa 100644 (file)
@@ -1341,13 +1341,11 @@ udf_update_inode(struct inode *inode, int do_sync)
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
                fe->uid = cpu_to_le32(-1);
-       else if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
-               fe->uid = cpu_to_le32(inode->i_uid);
+       else fe->uid = cpu_to_le32(inode->i_uid);
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET))
                fe->gid = cpu_to_le32(-1);
-       else if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
-               fe->gid = cpu_to_le32(inode->i_gid);
+       else fe->gid = cpu_to_le32(inode->i_gid);
 
        udfperms =      ((inode->i_mode & S_IRWXO)     ) |
                        ((inode->i_mode & S_IRWXG) << 2) |
index 34f333b762a04b57e244ff0b2f9b2fe34df510c6..95707182b3ed3c7a7c7609d4307bc137c0572a48 100644 (file)
@@ -13,6 +13,8 @@
 #define POLLWRBAND     (1 << 9)
 #define POLLMSG                (1 << 10)
 #define POLLREMOVE     (1 << 11)
+#define POLLRDHUP       (1 << 12)
+
 
 struct pollfd {
        int fd;
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h b/include/asm-arm/arch-at91rm9200/at91rm9200_emac.h
new file mode 100644 (file)
index 0000000..fbc091e
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * include/asm-arm/arch-at91rm9200/at91rm9200_emac.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Ethernet MAC registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91RM9200_EMAC_H
+#define AT91RM9200_EMAC_H
+
+#define        AT91_EMAC_CTL           0x00    /* Control Register */
+#define                AT91_EMAC_LB            (1 <<  0)       /* Loopback */
+#define                AT91_EMAC_LBL           (1 <<  1)       /* Loopback Local */
+#define                AT91_EMAC_RE            (1 <<  2)       /* Receive Enable */
+#define                AT91_EMAC_TE            (1 <<  3)       /* Transmit Enable */
+#define                AT91_EMAC_MPE           (1 <<  4)       /* Management Port Enable */
+#define                AT91_EMAC_CSR           (1 <<  5)       /* Clear Statistics Registers */
+#define                AT91_EMAC_INCSTAT       (1 <<  6)       /* Increment Statistics Registers */
+#define                AT91_EMAC_WES           (1 <<  7)       /* Write Enable for Statistics Registers */
+#define                AT91_EMAC_BP            (1 <<  8)       /* Back Pressure */
+
+#define        AT91_EMAC_CFG           0x04    /* Configuration Register */
+#define                AT91_EMAC_SPD           (1 <<  0)       /* Speed */
+#define                AT91_EMAC_FD            (1 <<  1)       /* Full Duplex */
+#define                AT91_EMAC_BR            (1 <<  2)       /* Bit Rate */
+#define                AT91_EMAC_CAF           (1 <<  4)       /* Copy All Frames */
+#define                AT91_EMAC_NBC           (1 <<  5)       /* No Broadcast */
+#define                AT91_EMAC_MTI           (1 <<  6)       /* Multicast Hash Enable */
+#define                AT91_EMAC_UNI           (1 <<  7)       /* Unicast Hash Enable */
+#define                AT91_EMAC_BIG           (1 <<  8)       /* Receive 1522 Bytes */
+#define                AT91_EMAC_EAE           (1 <<  9)       /* External Address Match Enable */
+#define                AT91_EMAC_CLK           (3 << 10)       /* MDC Clock Divisor */
+#define                AT91_EMAC_CLK_DIV8              (0 << 10)
+#define                AT91_EMAC_CLK_DIV16             (1 << 10)
+#define                AT91_EMAC_CLK_DIV32             (2 << 10)
+#define                AT91_EMAC_CLK_DIV64             (3 << 10)
+#define                AT91_EMAC_RTY           (1 << 12)       /* Retry Test */
+#define                AT91_EMAC_RMII          (1 << 13)       /* Reduce MII (RMII) */
+
+#define        AT91_EMAC_SR            0x08    /* Status Register */
+#define                AT91_EMAC_SR_LINK       (1 <<  0)       /* Link */
+#define                AT91_EMAC_SR_MDIO       (1 <<  1)       /* MDIO pin */
+#define                AT91_EMAC_SR_IDLE       (1 <<  2)       /* PHY idle */
+
+#define        AT91_EMAC_TAR           0x0c    /* Transmit Address Register */
+
+#define        AT91_EMAC_TCR           0x10    /* Transmit Control Register */
+#define                AT91_EMAC_LEN           (0x7ff << 0)    /* Transmit Frame Length */
+#define                AT91_EMAC_NCRC          (1     << 15)   /* No CRC */
+
+#define        AT91_EMAC_TSR           0x14    /* Transmit Status Register */
+#define                AT91_EMAC_TSR_OVR       (1 <<  0)       /* Transmit Buffer Overrun */
+#define                AT91_EMAC_TSR_COL       (1 <<  1)       /* Collision Occurred */
+#define                AT91_EMAC_TSR_RLE       (1 <<  2)       /* Retry Limit Exceeded */
+#define                AT91_EMAC_TSR_IDLE      (1 <<  3)       /* Transmitter Idle */
+#define                AT91_EMAC_TSR_BNQ       (1 <<  4)       /* Transmit Buffer not Queued */
+#define                AT91_EMAC_TSR_COMP      (1 <<  5)       /* Transmit Complete */
+#define                AT91_EMAC_TSR_UND       (1 <<  6)       /* Transmit Underrun */
+
+#define        AT91_EMAC_RBQP          0x18    /* Receive Buffer Queue Pointer */
+
+#define        AT91_EMAC_RSR           0x20    /* Receive Status Register */
+#define                AT91_EMAC_RSR_BNA       (1 <<  0)       /* Buffer Not Available */
+#define                AT91_EMAC_RSR_REC       (1 <<  1)       /* Frame Received */
+#define                AT91_EMAC_RSR_OVR       (1 <<  2)       /* RX Overrun */
+
+#define        AT91_EMAC_ISR           0x24    /* Interrupt Status Register */
+#define                AT91_EMAC_DONE          (1 <<  0)       /* Management Done */
+#define                AT91_EMAC_RCOM          (1 <<  1)       /* Receive Complete */
+#define                AT91_EMAC_RBNA          (1 <<  2)       /* Receive Buffer Not Available */
+#define                AT91_EMAC_TOVR          (1 <<  3)       /* Transmit Buffer Overrun */
+#define                AT91_EMAC_TUND          (1 <<  4)       /* Transmit Buffer Underrun */
+#define                AT91_EMAC_RTRY          (1 <<  5)       /* Retry Limit */
+#define                AT91_EMAC_TBRE          (1 <<  6)       /* Transmit Buffer Register Empty */
+#define                AT91_EMAC_TCOM          (1 <<  7)       /* Transmit Complete */
+#define                AT91_EMAC_TIDLE         (1 <<  8)       /* Transmit Idle */
+#define                AT91_EMAC_LINK          (1 <<  9)       /* Link */
+#define                AT91_EMAC_ROVR          (1 << 10)       /* RX Overrun */
+#define                AT91_EMAC_ABT           (1 << 11)       /* Abort */
+
+#define        AT91_EMAC_IER           0x28    /* Interrupt Enable Register */
+#define        AT91_EMAC_IDR           0x2c    /* Interrupt Disable Register */
+#define        AT91_EMAC_IMR           0x30    /* Interrupt Mask Register */
+
+#define        AT91_EMAC_MAN           0x34    /* PHY Maintenance Register */
+#define                AT91_EMAC_DATA          (0xffff << 0)   /* MDIO Data */
+#define                AT91_EMAC_REGA          (0x1f   << 18)  /* MDIO Register */
+#define                AT91_EMAC_PHYA          (0x1f   << 23)  /* MDIO PHY Address */
+#define                AT91_EMAC_RW            (3      << 28)  /* Read/Write operation */
+#define                        AT91_EMAC_RW_W          (1 << 28)
+#define                        AT91_EMAC_RW_R          (2 << 28)
+#define                AT91_EMAC_MAN_802_3     0x40020000      /* IEEE 802.3 value */
+
+/*
+ * Statistics Registers.
+ */
+#define AT91_EMAC_FRA          0x40    /* Frames Transmitted OK */
+#define AT91_EMAC_SCOL         0x44    /* Single Collision Frame */
+#define AT91_EMAC_MCOL         0x48    /* Multiple Collision Frame */
+#define AT91_EMAC_OK           0x4c    /* Frames Received OK */
+#define AT91_EMAC_SEQE         0x50    /* Frame Check Sequence Error */
+#define AT91_EMAC_ALE          0x54    /* Alignmemt Error */
+#define AT91_EMAC_DTE          0x58    /* Deffered Transmission Frame */
+#define AT91_EMAC_LCOL         0x5c    /* Late Collision */
+#define AT91_EMAC_ECOL         0x60    /* Excessive Collision */
+#define AT91_EMAC_TUE          0x64    /* Transmit Underrun Error */
+#define AT91_EMAC_CSE          0x68    /* Carrier Sense Error */
+#define AT91_EMAC_DRFC         0x6c    /* Discard RX Frame */
+#define AT91_EMAC_ROV          0x70    /* Receive Overrun */
+#define AT91_EMAC_CDE          0x74    /* Code Error */
+#define AT91_EMAC_ELR          0x78    /* Excessive Length Error */
+#define AT91_EMAC_RJB          0x7c    /* Receive Jabber */
+#define AT91_EMAC_USF          0x80    /* Undersize Frame */
+#define AT91_EMAC_SQEE         0x84    /* SQE Test Error */
+
+/*
+ * Address Registers.
+ */
+#define AT91_EMAC_HSL          0x90    /* Hash Address Low [31:0] */
+#define AT91_EMAC_HSH          0x94    /* Hash Address High [63:32] */
+#define AT91_EMAC_SA1L         0x98    /* Specific Address 1 Low, bytes 0-3 */
+#define AT91_EMAC_SA1H         0x9c    /* Specific Address 1 High, bytes 4-5 */
+#define AT91_EMAC_SA2L         0xa0    /* Specific Address 2 Low, bytes 0-3 */
+#define AT91_EMAC_SA2H         0xa4    /* Specific Address 2 High, bytes 4-5 */
+#define AT91_EMAC_SA3L         0xa8    /* Specific Address 3 Low, bytes 0-3 */
+#define AT91_EMAC_SA3H         0xac    /* Specific Address 3 High, bytes 4-5 */
+#define AT91_EMAC_SA4L         0xb0    /* Specific Address 4 Low, bytes 0-3 */
+#define AT91_EMAC_SA4H         0xb4    /* Specific Address 4 High, bytes 4-5 */
+
+#endif
index 2744ca831f5d126130df470e06a4805c062c9832..5030b2b232a3c7433be4c96676da242e77155c90 100644 (file)
@@ -16,6 +16,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index fdfdab064a658a0d31465d29fa0a0636f8162abf..9ccb7f4190cafaae318e3e4eb2d784c8d13cb7a1 100644 (file)
@@ -15,6 +15,7 @@
 #define POLLWRNORM     0x0100
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index 1c0efc3e4be70e5fc067a4ee9d01cc0426471567..1b25d4cf498c4aab72193c3246c94f312d00b1eb 100644 (file)
@@ -15,6 +15,7 @@
 #define POLLWRBAND     512
 #define POLLMSG                1024
 #define POLLREMOVE     4096
+#define POLLRDHUP       8192
 
 struct pollfd {
        int fd;
index 8cbcd60e334fb293224789b2e8f753bc0730122e..c8fe8801d075819c3e069e720e7806604d6ea8b5 100644 (file)
@@ -12,6 +12,7 @@
 #define POLLRDBAND     128
 #define POLLWRBAND     256
 #define POLLMSG                0x0400
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index bf49ab8ad6da173f8c9d7313bf845e76a73aa922..fc52103b276ae0011a2dfcb755c5b201ae6ea161 100644 (file)
@@ -12,6 +12,7 @@
 #define POLLRDBAND     128
 #define POLLWRBAND     256
 #define POLLMSG                0x0400
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index aecc80a15d3687f6fdc6274e4a17bc08eb5f4210..2cd4929abd40426b3ad88ef33762c859227b497b 100644 (file)
@@ -16,6 +16,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index 160258a0528d2692292cd8d3941bf595e6fcfa31..bcaf9f1402427ddaef313f0d82306d58e6a7410e 100644 (file)
@@ -21,6 +21,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index 43b7acf732d57ae1310819edb022133fb6b1fb1f..9e0e700e727c94e2e160b7b1e717181ce142a190 100644 (file)
@@ -21,6 +21,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index c4b69c4a87e1a337d6c66b564f264d57ccd05fa2..0fb8843647f8a4a4bbafc74d99bda97e622db475 100644 (file)
@@ -13,6 +13,7 @@
 #define POLLWRBAND     256
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index a000f1f789e342b296b305879caa4f6b3921da6f..70881f8c5c5092e58e00df92ec21956abeb1586e 100644 (file)
@@ -17,6 +17,7 @@
 /* These seem to be more or less nonstandard ...  */
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index 1c1da86934cffc08326f181478f437c50b502faa..20e4d03c74cb835d7d873015456aa26a0b67a6c6 100644 (file)
@@ -16,6 +16,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index edd2054da86b49d3b83503b7aed2962ab3f416af..9c7d1263103353745dfb10cece78ac1e3719d976 100644 (file)
@@ -13,6 +13,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index e90a5ca4206193716cf4490270ce9a4e2ae55f82..6f7f65ac7d27da520ca756590ba1495076dd34a2 100644 (file)
@@ -24,6 +24,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index 52f95b9188dcfe1105901a28a718424f500127f5..dbca9b32f4a6c4ff0f9f5f250e218e3eed4a0846 100644 (file)
@@ -16,6 +16,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index a420d14eb704a548ffb5591fa9521a5d5b657adb..3a6cbad08d281a9bc2a94a3b7fdc0397eca31502 100644 (file)
@@ -26,6 +26,7 @@
 #define POLLWRNORM     0x0100
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index ec0d9ef90a3bce4dc03bd405bf944fa20d65d324..a2c4d51d36c4c478f81dc0ba99a05a8809690137 100644 (file)
@@ -18,6 +18,7 @@ typedef struct {
        unsigned int counter;
        int prom_node;
        int mid;
+       int next;
 } cpuinfo_sparc;
 
 DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
index 3ddcc6481f0973d3441c7a18605e843fbfcf4a8f..26f13fb35497f77926404a6503e7b091c1f5a425 100644 (file)
@@ -13,6 +13,7 @@
 #define POLLWRBAND     256
 #define POLLMSG                512
 #define POLLREMOVE     1024
+#define POLLRDHUP       2048
 
 struct pollfd {
        int fd;
index 580c51d011dfd56d6bf33ddcaf5e5355ea5b2b26..98c46e3fbe8a2faae8bb92f3e2d66889a624f9da 100644 (file)
@@ -81,16 +81,9 @@ static inline int smp_call_function(void (*func)(void *info), void *info, int no
        return 0;
 }
 
-extern __volatile__ int __cpu_number_map[NR_CPUS];
-extern __volatile__ int __cpu_logical_map[NR_CPUS];
-
 static inline int cpu_logical_map(int cpu)
 {
-       return __cpu_logical_map[cpu];
-}
-static inline int cpu_number_map(int cpu)
-{
-       return __cpu_number_map[cpu];
+       return cpu;
 }
 
 static inline int hard_smp4m_processor_id(void)
index e344c98a6f5f98145cf4d73fc97c89f02fc59255..3350c90c7869f5da811f8fcb9df38716aec590d0 100644 (file)
@@ -94,7 +94,7 @@ static inline void __read_lock(raw_rwlock_t *rw)
 #define __raw_read_lock(lock) \
 do {   unsigned long flags; \
        local_irq_save(flags); \
-       __raw_read_lock(lock); \
+       __read_lock(lock); \
        local_irq_restore(flags); \
 } while(0)
 
@@ -114,11 +114,11 @@ static inline void __read_unlock(raw_rwlock_t *rw)
 #define __raw_read_unlock(lock) \
 do {   unsigned long flags; \
        local_irq_save(flags); \
-       __raw_read_unlock(lock); \
+       __read_unlock(lock); \
        local_irq_restore(flags); \
 } while(0)
 
-extern __inline__ void __raw_write_lock(raw_rwlock_t *rw)
+static inline void __raw_write_lock(raw_rwlock_t *rw)
 {
        register raw_rwlock_t *lp asm("g1");
        lp = rw;
@@ -131,9 +131,28 @@ extern __inline__ void __raw_write_lock(raw_rwlock_t *rw)
        : "g2", "g4", "memory", "cc");
 }
 
+static inline int __raw_write_trylock(raw_rwlock_t *rw)
+{
+       unsigned int val;
+
+       __asm__ __volatile__("ldstub [%1 + 3], %0"
+                            : "=r" (val)
+                            : "r" (&rw->lock)
+                            : "memory");
+
+       if (val == 0) {
+               val = rw->lock & ~0xff;
+               if (val)
+                       ((volatile u8*)&rw->lock)[3] = 0;
+       }
+
+       return (val == 0);
+}
+
 #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0)
 
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
 
 #endif /* !(__ASSEMBLY__) */
 
index 31b611aa74685d61ac7f244d6429298cc8bac450..ab6b0d1bb4adb6c0d2b1599fc951e5a5b7399896 100644 (file)
@@ -13,6 +13,7 @@
 #define POLLWRBAND     256
 #define POLLMSG                512
 #define POLLREMOVE     1024
+#define POLLRDHUP       2048
 
 struct pollfd {
        int fd;
index 0369562c7e1588db6fe077a723096cba9eb60f2e..c10176c2c28ff7b7b15a05e3e600399948a59966 100644 (file)
@@ -13,6 +13,7 @@
 #define POLLWRBAND     0x0100
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index c43cbba31913dbaf0809938cacb272526c4ab8fe..c0475a9d8bb860d0e330a866b6d6576b9a99d114 100644 (file)
@@ -16,6 +16,7 @@
 #define POLLWRBAND     0x0200
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x1000
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index dffe447534e063d58d480937515691f415ca8927..6fd94773e866051bef79e0cff38fe5d6e0b04e6b 100644 (file)
@@ -27,6 +27,7 @@
 
 #define POLLMSG                0x0400
 #define POLLREMOVE     0x0800
+#define POLLRDHUP       0x2000
 
 struct pollfd {
        int fd;
index 208650b1ad3ac08a340d93e87729890d807a3bdb..f17525a963d1954821386355da95077660fa43cf 100644 (file)
@@ -175,4 +175,11 @@ static inline __u32 ror32(__u32 word, unsigned int shift)
        return (word >> shift) | (word << (32 - shift));
 }
 
+static inline unsigned fls_long(unsigned long l)
+{
+       if (sizeof(l) == 4)
+               return fls(l);
+       return fls64(l);
+}
+
 #endif
index 5a23ce7526292fa6e406ccae0ea3926b5bb210e3..6548b35ab9f685d3f7a215cea8b2bfc557a1ac17 100644 (file)
@@ -357,7 +357,8 @@ static inline kernel_cap_t cap_invert(kernel_cap_t c)
 
 #define cap_is_fs_cap(c)     (CAP_TO_MASK(c) & CAP_FS_MASK)
 
-extern int capable(int cap);
+int capable(int cap);
+int __capable(struct task_struct *t, int cap);
 
 #endif /* __KERNEL__ */
 
index d612b89dce3320db7d4edafe02dde8d50f8def56..08d50c53aab401ef79c20e85213027d854e5d199 100644 (file)
@@ -74,7 +74,6 @@ extern int lock_cpu_hotplug_interruptible(void);
        register_cpu_notifier(&fn##_nb);                        \
 }
 int cpu_down(unsigned int cpu);
-extern int __attribute__((weak)) smp_prepare_cpu(int cpu);
 #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
 #define lock_cpu_hotplug()     do { } while (0)
index 60e56c6e03dd3ee6c4836031b88626eaba249b1e..99e6115d8e526cfc53deeaf1e0c27879428b56ab 100644 (file)
@@ -212,17 +212,15 @@ static inline void __cpus_shift_left(cpumask_t *dstp,
        bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
 }
 
-#define first_cpu(src) __first_cpu(&(src), NR_CPUS)
-static inline int __first_cpu(const cpumask_t *srcp, int nbits)
-{
-       return min_t(int, nbits, find_first_bit(srcp->bits, nbits));
-}
-
-#define next_cpu(n, src) __next_cpu((n), &(src), NR_CPUS)
-static inline int __next_cpu(int n, const cpumask_t *srcp, int nbits)
-{
-       return min_t(int, nbits, find_next_bit(srcp->bits, nbits, n+1));
-}
+#ifdef CONFIG_SMP
+int __first_cpu(const cpumask_t *srcp);
+#define first_cpu(src) __first_cpu(&(src))
+int __next_cpu(int n, const cpumask_t *srcp);
+#define next_cpu(n, src) __next_cpu((n), &(src))
+#else
+#define first_cpu(src)         0
+#define next_cpu(n, src)       1
+#endif
 
 #define cpumask_of_cpu(cpu)                                            \
 ({                                                                     \
@@ -398,27 +396,17 @@ extern cpumask_t cpu_present_map;
 #define cpu_present(cpu)       ((cpu) == 0)
 #endif
 
-#define any_online_cpu(mask)                   \
-({                                             \
-       int cpu;                                \
-       for_each_cpu_mask(cpu, (mask))          \
-               if (cpu_online(cpu))            \
-                       break;                  \
-       cpu;                                    \
-})
+#ifdef CONFIG_SMP
+int highest_possible_processor_id(void);
+#define any_online_cpu(mask) __any_online_cpu(&(mask))
+int __any_online_cpu(const cpumask_t *mask);
+#else
+#define highest_possible_processor_id()        0
+#define any_online_cpu(mask)           0
+#endif
 
 #define for_each_cpu(cpu)        for_each_cpu_mask((cpu), cpu_possible_map)
 #define for_each_online_cpu(cpu)  for_each_cpu_mask((cpu), cpu_online_map)
 #define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map)
 
-/* Find the highest possible smp_processor_id() */
-#define highest_possible_processor_id() \
-({ \
-       unsigned int cpu, highest = 0; \
-       for_each_cpu_mask(cpu, cpu_possible_map) \
-               highest = cpu; \
-       highest; \
-})
-
-
 #endif /* __LINUX_CPUMASK_H */
index 4361f3789975d366a39a762d688d02df9408eb82..d10bd30c337e2ca56da7a33cac3be9e83deab955 100644 (file)
@@ -162,6 +162,8 @@ d_iput:             no              no              no       yes
 #define DCACHE_REFERENCED      0x0008  /* Recently used, don't discard. */
 #define DCACHE_UNHASHED                0x0010  
 
+#define DCACHE_INOTIFY_PARENT_WATCHED  0x0020 /* Parent inode is watched */
+
 extern spinlock_t dcache_lock;
 
 /**
index fae9395fcf4f0e9baaef33c9f7fa84f0dd50a3f4..1e65ebc2a3dbb5496d8ca6e82d091e25f9160ccd 100644 (file)
@@ -276,37 +276,5 @@ static inline void dio_set_drvdata (struct dio_dev *d, void *data)
        dev_set_drvdata(&d->dev, data);
 }
 
-/*
- * A helper function which helps ensure correct dio_driver
- * setup and cleanup for commonly-encountered hotplug/modular cases
- *
- * This MUST stay in a header, as it checks for -DMODULE
- */
-static inline int dio_module_init(struct dio_driver *drv)
-{
-       int rc = dio_register_driver(drv);
-
-       if (rc > 0)
-               return 0;
-
-       /* iff CONFIG_HOTPLUG and built into kernel, we should
-        * leave the driver around for future hotplug events.
-        * For the module case, a hotplug daemon of some sort
-        * should load a module in response to an insert event. */
-#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
-       if (rc == 0)
-               return 0;
-#else
-       if (rc == 0)
-               rc = -ENODEV;
-#endif
-
-       /* if we get here, we need to clean up DIO driver instance
-        * and return some sort of error */
-       dio_unregister_driver(drv);
-
-       return rc;
-}
-
 #endif /* __KERNEL__ */
 #endif /* ndef _LINUX_DIO_H */
index 215696a0f16f8c53551d191780109917bf203c3b..21e8cf795c38ddc139090b84ec91c50a14487d01 100644 (file)
@@ -65,6 +65,11 @@ extern int dir_notify_enable;
 #define FMODE_PREAD    8
 #define FMODE_PWRITE   FMODE_PREAD     /* These go hand in hand */
 
+/* File is being opened for execution. Primary users of this flag are
+   distributed filesystems that can use it to achieve correct ETXTBUSY
+   behavior for cross-node execution/opening_for_writing of files */
+#define FMODE_EXEC     16
+
 #define RW_MASK                1
 #define RWA_MASK       2
 #define READ 0
@@ -1558,7 +1563,6 @@ extern void destroy_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
 extern int remove_suid(struct dentry *);
 extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
-extern struct mutex iprune_mutex;
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 extern void remove_inode_hash(struct inode *);
index 03b8e7932b830a3f1bfffcc531ec4ee9b1662b1e..f7e517c1f1bdb493d9e02c729afc6f6755d24252 100644 (file)
 #include <linux/dnotify.h>
 #include <linux/inotify.h>
 
+/*
+ * fsnotify_d_instantiate - instantiate a dentry for inode
+ * Called with dcache_lock held.
+ */
+static inline void fsnotify_d_instantiate(struct dentry *entry,
+                                               struct inode *inode)
+{
+       inotify_d_instantiate(entry, inode);
+}
+
+/*
+ * fsnotify_d_move - entry has been moved
+ * Called with dcache_lock and entry->d_lock held.
+ */
+static inline void fsnotify_d_move(struct dentry *entry)
+{
+       inotify_d_move(entry);
+}
+
 /*
  * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
  */
index ec311bc89439fc7c2b710947f40ff385391ffc15..679b46a6a565ccdad994bc245b438d80003be870 100644 (file)
 #define I2C_HW_B_SAVAGE                0x01001d /* savage framebuffer driver */
 #define I2C_HW_B_RADEON                0x01001e /* radeon framebuffer driver */
 #define I2C_HW_B_EM28XX                0x01001f /* em28xx video capture cards */
+#define I2C_HW_B_CX2341X       0x010020 /* Conexant CX2341X MPEG encoder cards */
 
 /* --- PCF 8584 based algorithms                                       */
 #define I2C_HW_P_LP            0x020000 /* Parallel port interface */
index ff8d8b8632f49bf8a8e3825ba1f3535a7ca41b4e..ed0ac7c39fdc49bc83c9db2dc885d1ec63046873 100644 (file)
@@ -69,6 +69,10 @@ extern initcall_t __security_initcall_start[], __security_initcall_end[];
 
 /* Defined in init/main.c */
 extern char saved_command_line[];
+
+/* used by init/main.c */
+extern void setup_arch(char **);
+
 #endif
   
 #ifndef MODULE
index 267c88b5f742592b69dabf70bfcdfb2c471ec706..09e00433c78e267b37b3f485c0d877de780a0674 100644 (file)
@@ -71,6 +71,8 @@ struct inotify_event {
 
 #ifdef CONFIG_INOTIFY
 
+extern void inotify_d_instantiate(struct dentry *, struct inode *);
+extern void inotify_d_move(struct dentry *);
 extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
                                      const char *);
 extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
@@ -81,6 +83,15 @@ extern u32 inotify_get_cookie(void);
 
 #else
 
+static inline void inotify_d_instantiate(struct dentry *dentry,
+                                       struct inode *inode)
+{
+}
+
+static inline void inotify_d_move(struct dentry *dentry)
+{
+}
+
 static inline void inotify_inode_queue_event(struct inode *inode,
                                             __u32 mask, __u32 cookie,
                                             const char *filename)
index 6c5d4c898ccb2bb5f54ec9f07a704eda70cb68f2..ee2a82a572f7d7b6b95c6ea593e1e65f85fb89d9 100644 (file)
@@ -114,53 +114,8 @@ static inline void set_native_irq_info(int irq, cpumask_t mask)
 #if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
 extern cpumask_t pending_irq_cpumask[NR_IRQS];
 
-static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
-{
-       irq_desc_t *desc = irq_desc + irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&desc->lock, flags);
-       desc->move_irq = 1;
-       pending_irq_cpumask[irq] = mask;
-       spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-static inline void
-move_native_irq(int irq)
-{
-       cpumask_t tmp;
-       irq_desc_t *desc = irq_descp(irq);
-
-       if (likely (!desc->move_irq))
-               return;
-
-       desc->move_irq = 0;
-
-       if (likely(cpus_empty(pending_irq_cpumask[irq])))
-               return;
-
-       if (!desc->handler->set_affinity)
-               return;
-
-       /* note - we hold the desc->lock */
-       cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
-
-       /*
-        * If there was a valid mask to work with, please
-        * do the disable, re-program, enable sequence.
-        * This is *not* particularly important for level triggered
-        * but in a edge trigger case, we might be setting rte
-        * when an active trigger is comming in. This could
-        * cause some ioapics to mal-function.
-        * Being paranoid i guess!
-        */
-       if (unlikely(!cpus_empty(tmp))) {
-               desc->handler->disable(irq);
-               desc->handler->set_affinity(irq,tmp);
-               desc->handler->enable(irq);
-       }
-       cpus_clear(pending_irq_cpumask[irq]);
-}
+void set_pending_irq(unsigned int irq, cpumask_t mask);
+void move_native_irq(int irq);
 
 #ifdef CONFIG_PCI_MSI
 /*
index 2ccbfb6340ba7cd192246eb4d37c7184408ae49b..4fc7dffd66efecb37424da50cd8d718677fb22e4 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/stddef.h>
 #include <linux/bit_spinlock.h>
 #include <linux/mutex.h>
+#include <linux/timer.h>
+
 #include <asm/semaphore.h>
 #endif
 
@@ -787,7 +789,7 @@ struct journal_s
        unsigned long           j_commit_interval;
 
        /* The timer used to wakeup the commit thread: */
-       struct timer_list       *j_commit_timer;
+       struct timer_list       j_commit_timer;
 
        /*
         * The revoke table: maintains the list of revoked blocks in the
index bb6e7ddee2fd456ff107e54aac6bc04dde588f0d..03d6cfaa5b8ab2d9e76f8717af5d1fa1c493f70e 100644 (file)
@@ -154,9 +154,10 @@ static inline int __attribute_pure__ long_log2(unsigned long x)
        return r;
 }
 
-static inline unsigned long __attribute_const__ roundup_pow_of_two(unsigned long x)
+static inline unsigned long
+__attribute_const__ roundup_pow_of_two(unsigned long x)
 {
-       return (1UL << fls(x - 1));
+       return 1UL << fls_long(x - 1);
 }
 
 extern int printk_ratelimit(void);
index e36a46702d9411085773744b46e6afc45728618f..0a74c52924c9d60e6feb8668b4cbf3b1046d7dc3 100644 (file)
 
 #define UBD_MAJOR              98
 
+#define PP_MAJOR               99
 #define JSFD_MAJOR             99
 
 #define PHONE_MAJOR            100
index 70bd843c71cb83872e7a9190365ed3a870fd5d1d..eaec13ddd6670bb8f9d41ef68a3faf3c7d06a5bb 100644 (file)
@@ -183,6 +183,7 @@ void *__symbol_get_gpl(const char *symbol);
 
 /* For every exported symbol, place a struct in the __ksymtab section */
 #define __EXPORT_SYMBOL(sym, sec)                              \
+       extern typeof(sym) sym;                                 \
        __CRC_SYMBOL(sym, sec)                                  \
        static const char __kstrtab_##sym[]                     \
        __attribute__((section("__ksymtab_strings")))           \
@@ -554,25 +555,6 @@ static inline void module_remove_driver(struct device_driver *driver)
 
 /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */
 
-struct obsolete_modparm {
-       char name[64];
-       char type[64-sizeof(void *)];
-       void *addr;
-};
-
-static inline void MODULE_PARM_(void) { }
-#ifdef MODULE
-/* DEPRECATED: Do not use. */
-#define MODULE_PARM(var,type)                                              \
-extern struct obsolete_modparm __parm_##var \
-__attribute__((section("__obsparm"))); \
-struct obsolete_modparm __parm_##var = \
-{ __stringify(var), type, &MODULE_PARM_ }; \
-__MODULE_PARM_TYPE(var, type);
-#else
-#define MODULE_PARM(var,type) static void __attribute__((__unused__)) *__parm_##var = &MODULE_PARM_;
-#endif
-
 #define __MODULE_STRING(x) __stringify(x)
 
 /* Use symbol_get and symbol_put instead.  You'll thank me. */
index b5c98c43779e4ada67ae76132ed0279967a48f9a..7c0c2c198f1f64400cb269d2e9608031e690ea30 100644 (file)
@@ -162,13 +162,6 @@ extern int param_array_get(char *buffer, struct kernel_param *kp);
 extern int param_set_copystring(const char *val, struct kernel_param *kp);
 extern int param_get_string(char *buffer, struct kernel_param *kp);
 
-int param_array(const char *name,
-               const char *val,
-               unsigned int min, unsigned int max,
-               void *elem, int elemsize,
-               int (*set)(const char *, struct kernel_param *kp),
-               int *num);
-
 /* for exporting parameters in /sys/parameters */
 
 struct module;
index 141c96586824b4e8404ddee8e2d8ca64e5985c8c..f376a7598a782139affd060cd36323df7306c54d 100644 (file)
@@ -14,8 +14,6 @@
  * Added PPGETMODES/PPGETMODE/PPGETPHASE, Fred Barnes <frmb2@ukc.ac.uk>, 03/01/2001
  */
 
-#define PP_MAJOR       99
-
 #define PP_IOCTL       'p'
 
 /* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */
index 8dc2d04a103f48b384e20409483f15b7e32e1b6c..2dab71e1c3d12565cf428084e7716274b257be57 100644 (file)
@@ -209,7 +209,6 @@ extern struct dqstats dqstats;
 #define DQ_FAKE_B      3       /* no limits only usage */
 #define DQ_READ_B      4       /* dquot was read into memory */
 #define DQ_ACTIVE_B    5       /* dquot is active (dquot_release not called) */
-#define DQ_WAITFREE_B  6       /* dquot being waited (by invalidate_dquots) */
 
 struct dquot {
        struct hlist_node dq_hash;      /* Hash list in memory */
index c57ff2fcb30a8d27990a2d4f5acc516714203b99..dd83cca2800160bca6940abe03b73165383fb6ff 100644 (file)
@@ -45,6 +45,8 @@ do {                                                                  \
        (root)->rnode = NULL;                                           \
 } while (0)
 
+#define RADIX_TREE_MAX_TAGS 2
+
 int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
 void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
 void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long);
@@ -55,15 +57,16 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 int radix_tree_preload(gfp_t gfp_mask);
 void radix_tree_init(void);
 void *radix_tree_tag_set(struct radix_tree_root *root,
-                       unsigned long index, int tag);
+                       unsigned long index, unsigned int tag);
 void *radix_tree_tag_clear(struct radix_tree_root *root,
-                       unsigned long index, int tag);
+                       unsigned long index, unsigned int tag);
 int radix_tree_tag_get(struct radix_tree_root *root,
-                       unsigned long index, int tag);
+                       unsigned long index, unsigned int tag);
 unsigned int
 radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
-               unsigned long first_index, unsigned int max_items, int tag);
-int radix_tree_tagged(struct radix_tree_root *root, int tag);
+               unsigned long first_index, unsigned int max_items,
+               unsigned int tag);
+int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
 
 static inline void radix_tree_preload_end(void)
 {
index dad78cecfd207c079339e8956c8a1812240c7070..912f1b7cb18f375123b99efa0046fc793491a7ff 100644 (file)
@@ -1704,6 +1704,11 @@ static inline int reiserfs_transaction_running(struct super_block *s)
        return 0;
 }
 
+static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th)
+{
+       return th->t_blocks_allocated - th->t_blocks_logged;
+}
+
 int reiserfs_async_progress_wait(struct super_block *s);
 
 struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
index 87280eb6083d44b94133c635b4916255e60b93cb..5353afb11db391671a6957ac0500f09ca0b12b38 100644 (file)
@@ -101,13 +101,13 @@ static inline void reiserfs_mark_inode_private(struct inode *inode)
 #else
 
 #define is_reiserfs_priv_object(inode) 0
-#define reiserfs_mark_inode_private(inode)
+#define reiserfs_mark_inode_private(inode) do {;} while(0)
 #define reiserfs_getxattr NULL
 #define reiserfs_setxattr NULL
 #define reiserfs_listxattr NULL
 #define reiserfs_removexattr NULL
-#define reiserfs_write_lock_xattrs(sb)
-#define reiserfs_write_unlock_xattrs(sb)
+#define reiserfs_write_lock_xattrs(sb) do {;} while(0)
+#define reiserfs_write_unlock_xattrs(sb) do {;} while(0)
 #define reiserfs_read_lock_xattrs(sb)
 #define reiserfs_read_unlock_xattrs(sb)
 
index b18eb8cfa6391e12c395dee2758a7633be762669..3c19be35124b03b2526fb803ef93a45b92c26896 100644 (file)
@@ -1040,6 +1040,11 @@ struct swap_info_struct;
  *     @effective contains the effective capability set.
  *     @inheritable contains the inheritable capability set.
  *     @permitted contains the permitted capability set.
+ * @capable:
+ *     Check whether the @tsk process has the @cap capability.
+ *     @tsk contains the task_struct for the process.
+ *     @cap contains the capability <include/linux/capability.h>.
+ *     Return 0 if the capability is granted for @tsk.
  * @acct:
  *     Check permission before enabling or disabling process accounting.  If
  *     accounting is being enabled, then @file refers to the open file used to
@@ -1053,11 +1058,6 @@ struct swap_info_struct;
  *     @table contains the ctl_table structure for the sysctl variable.
  *     @op contains the operation (001 = search, 002 = write, 004 = read).
  *     Return 0 if permission is granted.
- * @capable:
- *     Check whether the @tsk process has the @cap capability.
- *     @tsk contains the task_struct for the process.
- *     @cap contains the capability <include/linux/capability.h>.
- *     Return 0 if the capability is granted for @tsk.
  * @syslog:
  *     Check permission before accessing the kernel message ring or changing
  *     logging to the console.
@@ -1099,9 +1099,9 @@ struct security_operations {
                            kernel_cap_t * effective,
                            kernel_cap_t * inheritable,
                            kernel_cap_t * permitted);
+       int (*capable) (struct task_struct * tsk, int cap);
        int (*acct) (struct file * file);
        int (*sysctl) (struct ctl_table * table, int op);
-       int (*capable) (struct task_struct * tsk, int cap);
        int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
        int (*quota_on) (struct dentry * dentry);
        int (*syslog) (int type);
@@ -1347,6 +1347,11 @@ static inline void security_capset_set (struct task_struct *target,
        security_ops->capset_set (target, effective, inheritable, permitted);
 }
 
+static inline int security_capable(struct task_struct *tsk, int cap)
+{
+       return security_ops->capable(tsk, cap);
+}
+
 static inline int security_acct (struct file *file)
 {
        return security_ops->acct (file);
@@ -2050,6 +2055,11 @@ static inline void security_capset_set (struct task_struct *target,
        cap_capset_set (target, effective, inheritable, permitted);
 }
 
+static inline int security_capable(struct task_struct *tsk, int cap)
+{
+       return cap_capable(tsk, cap);
+}
+
 static inline int security_acct (struct file *file)
 {
        return 0;
index e2ee5b268797884427a4f81aff347980136de3e0..15e1d9736b1bb9fc130b27a81fdb8109b7fe02b5 100644 (file)
@@ -64,6 +64,7 @@ extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned lo
 extern int kmem_cache_destroy(kmem_cache_t *);
 extern int kmem_cache_shrink(kmem_cache_t *);
 extern void *kmem_cache_alloc(kmem_cache_t *, gfp_t);
+extern void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
 extern void kmem_cache_free(kmem_cache_t *, void *);
 extern unsigned int kmem_cache_size(kmem_cache_t *);
 extern const char *kmem_cache_name(kmem_cache_t *);
@@ -77,11 +78,12 @@ struct cache_sizes {
 };
 extern struct cache_sizes malloc_sizes[];
 
-#ifndef CONFIG_DEBUG_SLAB
 extern void *__kmalloc(size_t, gfp_t);
+#ifndef CONFIG_DEBUG_SLAB
+#define ____kmalloc(size, flags) __kmalloc(size, flags)
 #else
 extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
-#define __kmalloc(size, flags) \
+#define ____kmalloc(size, flags) \
     __kmalloc_track_caller(size, flags, __builtin_return_address(0))
 #endif
 
@@ -108,7 +110,30 @@ found:
        return __kmalloc(size, flags);
 }
 
-extern void *kzalloc(size_t, gfp_t);
+extern void *__kzalloc(size_t, gfp_t);
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+       if (__builtin_constant_p(size)) {
+               int i = 0;
+#define CACHE(x) \
+               if (size <= x) \
+                       goto found; \
+               else \
+                       i++;
+#include "kmalloc_sizes.h"
+#undef CACHE
+               {
+                       extern void __you_cannot_kzalloc_that_much(void);
+                       __you_cannot_kzalloc_that_much();
+               }
+found:
+               return kmem_cache_zalloc((flags & GFP_DMA) ?
+                       malloc_sizes[i].cs_dmacachep :
+                       malloc_sizes[i].cs_cachep, flags);
+       }
+       return __kzalloc(size, flags);
+}
 
 /**
  * kcalloc - allocate memory for an array. The memory is set to zero.
@@ -155,17 +180,18 @@ struct kmem_cache *kmem_cache_create(const char *c, size_t, size_t,
        void (*)(void *, struct kmem_cache *, unsigned long));
 int kmem_cache_destroy(struct kmem_cache *c);
 void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags);
+void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
 void kmem_cache_free(struct kmem_cache *c, void *b);
 const char *kmem_cache_name(struct kmem_cache *);
 void *kmalloc(size_t size, gfp_t flags);
-void *kzalloc(size_t size, gfp_t flags);
+void *__kzalloc(size_t size, gfp_t flags);
 void kfree(const void *m);
 unsigned int ksize(const void *m);
 unsigned int kmem_cache_size(struct kmem_cache *c);
 
 static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
 {
-       return kzalloc(n * size, flags);
+       return __kzalloc(n * size, flags);
 }
 
 #define kmem_cache_shrink(d) (0)
@@ -173,6 +199,8 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
 #define kmem_ptr_validate(a, b) (0)
 #define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f)
 #define kmalloc_node(s, f, n) kmalloc(s, f)
+#define kzalloc(s, f) __kzalloc(s, f)
+#define ____kmalloc kmalloc
 
 #endif /* CONFIG_SLOB */
 
index d9cdba54b7893196297d49d3c2dd787270d5d272..bf0e785e2e03bb9066eff3a08105cf246736809c 100644 (file)
@@ -101,6 +101,7 @@ extern long do_utimes(int dfd, char __user *filename, struct timeval *times);
 struct itimerval;
 extern int do_setitimer(int which, struct itimerval *value,
                        struct itimerval *ovalue);
+extern unsigned int alarm_setitimer(unsigned int seconds);
 extern int do_getitimer(int which, struct itimerval *value);
 extern void getnstimeofday(struct timespec *tv);
 
index b7ca1204e42ac6efedc5ad6a5fd78dfb8e67c549..82dc9ae79d37115867bb5275797e2173c605bd1f 100644 (file)
 
 #define MAXPHASE 512000L        /* max phase error (us) */
 #define MAXFREQ (512L << SHIFT_USEC)  /* max frequency error (ppm) */
-#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
 #define MINSEC 16L              /* min interval between updates (s) */
 #define MAXSEC 1200L            /* max interval between updates (s) */
 #define        NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
 
-/*
- * The following defines are used only if a pulse-per-second (PPS)
- * signal is available and connected via a modem control lead, such as
- * produced by the optional ppsclock feature incorporated in the Sun
- * asynch driver. They establish the design parameters of the frequency-
- * lock loop used to discipline the CPU clock oscillator to the PPS
- * signal.
- *
- * PPS_AVG is the averaging factor for the frequency loop, as well as
- * the time and frequency dispersion.
- *
- * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum
- * calibration intervals, respectively, in seconds as a power of two.
- *
- * PPS_VALID is the maximum interval before the PPS signal is considered
- * invalid and protocol updates used directly instead.
- *
- * MAXGLITCH is the maximum interval before a time offset of more than
- * MAXTIME is believed.
- */
-#define PPS_AVG 2              /* pps averaging constant (shift) */
-#define PPS_SHIFT 2            /* min interval duration (s) (shift) */
-#define PPS_SHIFTMAX 8         /* max interval duration (s) (shift) */
-#define PPS_VALID 120          /* pps signal watchdog max (s) */
-#define MAXGLITCH 30           /* pps signal glitch max (s) */
-
 /*
  * syscall interface - used (mainly by NTP daemon)
  * to discipline kernel clock oscillator
@@ -246,20 +219,6 @@ extern long time_reftime;  /* time at last adjustment (s) */
 extern long time_adjust;       /* The amount of adjtime left */
 extern long time_next_adjust;  /* Value for time_adjust at next tick */
 
-/* interface variables pps->timer interrupt */
-extern long pps_offset;                /* pps time offset (us) */
-extern long pps_jitter;                /* time dispersion (jitter) (us) */
-extern long pps_freq;          /* frequency offset (scaled ppm) */
-extern long pps_stabil;                /* frequency dispersion (scaled ppm) */
-extern long pps_valid;         /* pps signal watchdog counter */
-
-/* interface variables pps->adjtimex */
-extern int pps_shift;          /* interval duration (s) (shift) */
-extern long pps_jitcnt;                /* jitter limit exceeded */
-extern long pps_calcnt;                /* calibration intervals */
-extern long pps_errcnt;                /* calibration errors */
-extern long pps_stbcnt;                /* stability limit exceeded */
-
 /**
  * ntp_clear - Clears the NTP state variables
  *
index 0c6169fff366374aa929a36737a8e3f3386ab016..0976a163b459b79715f97c86af4a0c892eaf19fe 100644 (file)
@@ -2,8 +2,8 @@
 #define _LINUX_TTY_FLIP_H
 
 extern int tty_buffer_request_room(struct tty_struct *tty, size_t size);
-extern int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size);
-extern int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size);
+extern int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size);
+extern int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size);
 extern int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size);
 extern int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size);
 
index 1e7508420fcfb6fab284ab15203d1cb1670f4ac2..ffaf05679ffb2dad2e5d4ee58fc899bf35612e3d 100644 (file)
 
 #ifdef __KERNEL__
 
-#ifndef _ECMA_167_H
-typedef struct
-{
-       __u32                   logicalBlockNum;
-       __u16                   partitionReferenceNum;
-} __attribute__ ((packed)) lb_addr;
-
-typedef struct
-{
-       __u32                   extLength;
-       __u32                   extPosition;
-} __attribute__ ((packed)) short_ad;
-
-typedef struct
-{
-       __u32                   extLength;
-       lb_addr                 extLocation;
-       __u8                    impUse[6];
-} __attribute__ ((packed)) long_ad;
-#endif
-
 struct udf_inode_info
 {
        struct timespec         i_crtime;
index 724cfbf54b8afaf34edaae5593e4d6e5091107a6..2275bfec5b687e3c7545fc848346cc14a16d2ccc 100644 (file)
@@ -883,6 +883,7 @@ struct v4l2_modulator
 #define V4L2_TUNER_MODE_LANG2          0x0002
 #define V4L2_TUNER_MODE_SAP            0x0002
 #define V4L2_TUNER_MODE_LANG1          0x0003
+#define V4L2_TUNER_MODE_LANG1_LANG2    0x0004
 
 struct v4l2_frequency
 {
index ba5b72768bbe54de9aa6af922017c013971684c8..2f135cf6eef1600c947e983d59846fe7dedca4e6 100644 (file)
@@ -271,39 +271,6 @@ static inline void zorro_set_drvdata (struct zorro_dev *z, void *data)
 }
 
 
-/*
- * A helper function which helps ensure correct zorro_driver
- * setup and cleanup for commonly-encountered hotplug/modular cases
- *
- * This MUST stay in a header, as it checks for -DMODULE
- */
-static inline int zorro_module_init(struct zorro_driver *drv)
-{
-       int rc = zorro_register_driver(drv);
-
-       if (rc > 0)
-               return 0;
-
-       /* iff CONFIG_HOTPLUG and built into kernel, we should
-        * leave the driver around for future hotplug events.
-        * For the module case, a hotplug daemon of some sort
-        * should load a module in response to an insert event. */
-#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
-       if (rc == 0)
-               return 0;
-#else
-       if (rc == 0)
-               rc = -ENODEV;
-#endif
-
-       /* if we get here, we need to clean up Zorro driver instance
-        * and return some sort of error */
-       zorro_unregister_driver(drv);
-
-       return rc;
-}
-
-
     /*
      *  Bitmask indicating portions of available Zorro II RAM that are unused
      *  by the system. Every bit represents a 64K chunk, for a maximum of 8MB
index 295d256ee811c63f5b533906851926d63a2ab1e8..1fd4a2207574670846c9a85fbd43e99564d4e543 100644 (file)
@@ -21,18 +21,4 @@ enum audiochip {
        AUDIO_CHIP_MSP34XX
 };
 
-/* ---------------------------------------------------------------------- */
-
-/* audio inputs */
-#define AUDIO_TUNER        0x00
-#define AUDIO_RADIO        0x01
-#define AUDIO_EXTERN       0x02
-#define AUDIO_INTERN       0x03
-#define AUDIO_OFF          0x04
-#define AUDIO_ON           0x05
-#define AUDIO_EXTERN_1     AUDIO_EXTERN
-#define AUDIO_EXTERN_2     0x06
-#define AUDIO_MUTE         0x80
-#define AUDIO_UNMUTE       0x81
-
 #endif /* AUDIOCHIP_H */
diff --git a/include/media/cs53l32a.h b/include/media/cs53l32a.h
new file mode 100644 (file)
index 0000000..bf76197
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+    cs53l32a.h - definition for cs53l32a inputs and outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _CS53L32A_H_
+#define _CS53L32A_H_
+
+/* There are 2 physical inputs, but the second input can be
+   placed in two modes, the first mode bypasses the PGA (gain),
+   the second goes through the PGA. Hence there are three
+   possible inputs to choose from. */
+
+/* CS53L32A HW inputs */
+#define CS53L32A_IN0 0
+#define CS53L32A_IN1 1
+#define CS53L32A_IN2 2
+
+#endif
diff --git a/include/media/i2c-addr.h b/include/media/i2c-addr.h
new file mode 100644 (file)
index 0000000..e7ff44a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *     V4L I2C address list
+ *
+ *
+ *     Copyright (C) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *     Based on a previous mapping by
+ *     Ralph Metzler (rjkm@thp.uni-koeln.de)
+ *     Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+/* bttv address list */
+#define I2C_ADDR_TSA5522       0xc2
+#define I2C_ADDR_TDA7432       0x8a
+#define I2C_ADDR_BT832_ALT1    0x88
+#define I2C_ADDR_BT832_ALT2    0x8a // alternate setting
+#define I2C_ADDR_TDA8425       0x82
+#define I2C_ADDR_TDA9840       0x84
+#define I2C_ADDR_TDA9850       0xb6 /* also used by 9855,9873 */
+#define I2C_ADDR_TDA9874       0xb0 /* also used by 9875 */
+#define I2C_ADDR_TDA9875       0xb0
+#define I2C_ADDR_HAUPEE                0xa0
+#define I2C_ADDR_STBEE         0xae
+#define I2C_ADDR_VHX           0xc0
+#define I2C_ADDR_MSP3400       0x80
+#define I2C_ADDR_MSP3400_ALT   0x88
+#define I2C_ADDR_TEA6300       0x80 /* also used by 6320 */
+#define I2C_ADDR_DPL3518       0x84
+#define I2C_ADDR_TDA9887       0x86
+
+/*
+ * i2c bus addresses for the chips supported by tvaudio.c
+ */
+
+#define I2C_ADDR_TDA8425       0x82
+#define I2C_ADDR_TDA9840       0x84 /* also used by TA8874Z */
+#define I2C_ADDR_TDA985x_L     0xb4 /* also used by 9873 */
+#define I2C_ADDR_TDA985x_H     0xb6
+#define I2C_ADDR_TDA9874       0xb0 /* also used by 9875 */
+
+#define I2C_ADDR_TEA6300       0x80 /* also used by 6320 */
+#define I2C_ADDR_TEA6420       0x98
+
+#define I2C_ADDR_PIC16C54      0x96 /* PV951 */
diff --git a/include/media/msp3400.h b/include/media/msp3400.h
new file mode 100644 (file)
index 0000000..0be61a0
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+    msp3400.h - definition for msp3400 inputs and outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _MSP3400_H_
+#define _MSP3400_H_
+
+/* msp3400 routing
+   ===============
+
+   The msp3400 has a complicated routing scheme with many possible
+   combinations. The details are all in the datasheets but I will try
+   to give a short description here.
+
+   Inputs
+   ======
+
+   There are 1) tuner inputs, 2) I2S inputs, 3) SCART inputs. You will have
+   to select which tuner input to use and which SCART input to use. The
+   selected tuner input, the selected SCART input and all I2S inputs go to
+   the DSP (the tuner input first goes through the demodulator).
+
+   The DSP handles things like volume, bass/treble, balance, and some chips
+   have support for surround sound. It has several outputs: MAIN, AUX, I2S
+   and SCART1/2. Each output can select which DSP input to use. So the MAIN
+   output can select the tuner input while at the same time the SCART1 output
+   uses the I2S input.
+
+   Outputs
+   =======
+
+   Most DSP outputs are also the outputs of the msp3400. However, the SCART
+   outputs of the msp3400 can select which input to use: either the SCART1 or
+   SCART2 output from the DSP, or the msp3400 SCART inputs, thus completely
+   bypassing the DSP.
+
+   Summary
+   =======
+
+   So to specify a complete routing scheme for the msp3400 you will have to
+   specify in the 'input' field of the v4l2_routing struct:
+
+   1) which tuner input to use
+   2) which SCART input to use
+   3) which DSP input to use for each DSP output
+
+   And in the 'output' field of the v4l2_routing struct you specify:
+
+   1) which SCART input to use for each SCART output
+
+   Depending on how the msp is wired to the other components you can
+   ignore or mute certain inputs or outputs.
+
+   Also, depending on the msp version only a subset of the inputs or
+   outputs may be present. At the end of this header some tables are
+   added containing a list of what is available for each msp version.
+ */
+
+/* Inputs to the DSP unit: two independent selections have to be made:
+   1) the tuner (SIF) input
+   2) the SCART input
+   Bits 0-2 are used for the SCART input select, bit 3 is used for the tuner
+   input, bits 4-7 are reserved.
+ */
+
+/* SCART input to DSP selection */
+#define MSP_IN_SCART_1         0  /* Pin SC1_IN */
+#define MSP_IN_SCART_2         1  /* Pin SC2_IN */
+#define MSP_IN_SCART_3         2  /* Pin SC3_IN */
+#define MSP_IN_SCART_4         3  /* Pin SC4_IN */
+#define MSP_IN_MONO            6  /* Pin MONO_IN */
+#define MSP_IN_MUTE            7  /* Mute DSP input */
+#define MSP_SCART_TO_DSP(in)   (in)
+/* Tuner input to demodulator and DSP selection */
+#define MSP_IN_TUNER_1                 0  /* Analog Sound IF input pin ANA_IN1 */
+#define MSP_IN_TUNER_2         1  /* Analog Sound IF input pin ANA_IN2 */
+#define MSP_TUNER_TO_DSP(in)   ((in) << 3)
+
+/* The msp has up to 5 DSP outputs, each output can independently select
+   a DSP input.
+
+   The DSP outputs are: loudspeaker output (aka MAIN), headphones output
+   (aka AUX), SCART1 DA output, SCART2 DA output and an I2S output.
+   There also is a quasi-peak detector output, but that is not used by
+   this driver and is set to the same input as the loudspeaker output.
+   Not all outputs are supported by all msp models. Setting the input
+   of an unsupported output will be ignored by the driver.
+
+   There are up to 16 DSP inputs to choose from, so each output is
+   assigned 4 bits.
+
+   Note: the 44x8G can mix two inputs and feed the result back to the
+   DSP. This is currently not implemented. Also not implemented is the
+   multi-channel capable I2S3 input of the 44x0G. If someone can demonstrate
+   a need for one of those features then additional support can be added. */
+#define MSP_DSP_OUT_TUNER      0  /* Tuner output */
+#define MSP_DSP_OUT_SCART      2  /* SCART output */
+#define MSP_DSP_OUT_I2S1       5  /* I2S1 output */
+#define MSP_DSP_OUT_I2S2       6  /* I2S2 output */
+#define MSP_DSP_OUT_I2S3       7  /* I2S3 output */
+#define MSP_DSP_OUT_MAIN_AVC   11 /* MAIN AVC processed output */
+#define MSP_DSP_OUT_MAIN       12 /* MAIN output */
+#define MSP_DSP_OUT_AUX        13 /* AUX output */
+#define MSP_DSP_TO_MAIN(in)    ((in) << 4)
+#define MSP_DSP_TO_AUX(in)     ((in) << 8)
+#define MSP_DSP_TO_SCART1(in)  ((in) << 12)
+#define MSP_DSP_TO_SCART2(in)  ((in) << 16)
+#define MSP_DSP_TO_I2S(in)     ((in) << 20)
+
+/* Output SCART select: the SCART outputs can select which input
+   to use. */
+#define MSP_OUT_SCART1                 0  /* SCART1 input, bypassing the DSP */
+#define MSP_OUT_SCART2                 1  /* SCART2 input, bypassing the DSP */
+#define MSP_OUT_SCART3                 2  /* SCART3 input, bypassing the DSP */
+#define MSP_OUT_SCART4                 3  /* SCART4 input, bypassing the DSP */
+#define MSP_OUT_SCART1_DA      4  /* DSP SCART1 output */
+#define MSP_OUT_SCART2_DA      5  /* DSP SCART2 output */
+#define MSP_OUT_MONO           6  /* MONO input, bypassing the DSP */
+#define MSP_OUT_MUTE           7  /* MUTE output */
+#define MSP_OUT_TO_SCART1(in)          (in)
+#define MSP_OUT_TO_SCART2(in)          ((in) << 4)
+
+/* Shortcut macros */
+#define MSP_INPUT(sc, t, main_aux_src, sc_i2s_src) \
+       (MSP_SCART_TO_DSP(sc) | \
+        MSP_TUNER_TO_DSP(t) | \
+        MSP_DSP_TO_MAIN(main_aux_src) | \
+        MSP_DSP_TO_AUX(main_aux_src) | \
+        MSP_DSP_TO_SCART1(sc_i2s_src) | \
+        MSP_DSP_TO_SCART2(sc_i2s_src) | \
+        MSP_DSP_TO_I2S(sc_i2s_src))
+#define MSP_INPUT_DEFAULT MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1, \
+                                   MSP_DSP_OUT_TUNER, MSP_DSP_OUT_TUNER)
+#define MSP_OUTPUT(sc) \
+       (MSP_OUT_TO_SCART1(sc) | \
+        MSP_OUT_TO_SCART2(sc))
+/* This equals the RESET position of the msp3400 ACB register */
+#define MSP_OUTPUT_DEFAULT (MSP_OUT_TO_SCART1(MSP_OUT_SCART3) | \
+                           MSP_OUT_TO_SCART2(MSP_OUT_SCART1_DA))
+
+/* Tuner inputs vs. msp version */
+/* Chip      TUNER_1   TUNER_2
+   -------------------------
+   msp34x0b  y         y
+   msp34x0c  y         y
+   msp34x0d  y         y
+   msp34x5d  y         n
+   msp34x7d  y         n
+   msp34x0g  y         y
+   msp34x1g  y         y
+   msp34x2g  y         y
+   msp34x5g  y         n
+   msp34x7g  y         n
+   msp44x0g  y         y
+   msp44x8g  y         y
+ */
+
+/* SCART inputs vs. msp version */
+/* Chip      SC1 SC2 SC3 SC4
+   -------------------------
+   msp34x0b  y   y   y   n
+   msp34x0c  y   y   y   n
+   msp34x0d  y   y   y   y
+   msp34x5d  y   y   n   n
+   msp34x7d  y   n   n   n
+   msp34x0g  y   y   y   y
+   msp34x1g  y   y   y   y
+   msp34x2g  y   y   y   y
+   msp34x5g  y   y   n   n
+   msp34x7g  y   n   n   n
+   msp44x0g  y   y   y   y
+   msp44x8g  y   y   y   y
+ */
+
+/* DSP inputs vs. msp version (tuner and SCART inputs are always available) */
+/* Chip      I2S1 I2S2 I2S3 MAIN_AVC MAIN AUX
+   ------------------------------------------
+   msp34x0b  y    n    n    n        n    n
+   msp34x0c  y    y    n    n        n    n
+   msp34x0d  y    y    n    n        n    n
+   msp34x5d  y    y    n    n        n    n
+   msp34x7d  n    n    n    n        n    n
+   msp34x0g  y    y    n    n        n    n
+   msp34x1g  y    y    n    n        n    n
+   msp34x2g  y    y    n    y        y    y
+   msp34x5g  y    y    n    n        n    n
+   msp34x7g  n    n    n    n        n    n
+   msp44x0g  y    y    y    y        y    y
+   msp44x8g  y    y    y    n        n    n
+ */
+
+/* DSP outputs vs. msp version */
+/* Chip      MAIN AUX SCART1 SCART2 I2S
+   ------------------------------------
+   msp34x0b  y    y   y      n      y
+   msp34x0c  y    y   y      n      y
+   msp34x0d  y    y   y      y      y
+   msp34x5d  y    n   y      n      y
+   msp34x7d  y    n   y      n      n
+   msp34x0g  y    y   y      y      y
+   msp34x1g  y    y   y      y      y
+   msp34x2g  y    y   y      y      y
+   msp34x5g  y    n   y      n      y
+   msp34x7g  y    n   y      n      n
+   msp44x0g  y    y   y      y      y
+   msp44x8g  y    y   y      y      y
+ */
+
+#endif /* MSP3400_H */
+
diff --git a/include/media/rds.h b/include/media/rds.h
new file mode 100644 (file)
index 0000000..951c1ae
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+    Types and defines needed for RDS. This is included by
+    saa6588.c and every driver (e.g. bttv-driver.c) that wants
+    to use the saa6588 module.
+
+    Instead of having a seperate rds.h, I'd prefer to include
+    this stuff in one of the already existing files like tuner.h
+
+    (c) 2005 by Hans J. Koch
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _RDS_H
+#define _RDS_H
+
+struct rds_command {
+       unsigned int  block_count;
+       int           result;
+       unsigned char __user *buffer;
+       struct file   *instance;
+       poll_table    *event_list;
+};
+
+#define RDS_CMD_OPEN   _IOW('R',1,int)
+#define RDS_CMD_CLOSE  _IOW('R',2,int)
+#define RDS_CMD_READ   _IOR('R',3,int)
+#define RDS_CMD_POLL   _IOR('R',4,int)
+
+#endif
index e5e749e984ee7baf4864ac0ceea926130ec72c75..4507cb61ae9379e9e3c4715859854630c7b8c45d 100644 (file)
@@ -197,7 +197,8 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,
 void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi);
 int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf);
 void saa7146_buffer_timeout(unsigned long data);
-void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf);
+void saa7146_dma_free(struct saa7146_dev* dev,struct videobuf_queue *q,
+                                               struct saa7146_buf *buf);
 
 int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv);
 int saa7146_vv_release(struct saa7146_dev* dev);
diff --git a/include/media/tvaudio.h b/include/media/tvaudio.h
new file mode 100644 (file)
index 0000000..6915aaf
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+    tvaudio.h - definition for tvaudio inputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _TVAUDIO_H
+#define _TVAUDIO_H
+
+/* The tvaudio module accepts the following inputs: */
+#define TVAUDIO_INPUT_TUNER  0
+#define TVAUDIO_INPUT_RADIO  1
+#define TVAUDIO_INPUT_EXTERN 2
+#define TVAUDIO_INPUT_INTERN 3
+
+#endif
index 2360453e7496546b4c82cd885e2005e362096517..642520acdfa7b41da7a77cd78206b7a1b5d7ce77 100644 (file)
@@ -123,17 +123,6 @@ enum v4l2_chip_ident {
 /* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
 #define AUDC_SET_RADIO        _IO('d',88)
 
-/* select from TV,radio,extern,MUTE, to be replaced with VIDIOC_INT_S_AUDIO_ROUTING */
-#define AUDC_SET_INPUT        _IOW('d',89,int)
-
-/* msp3400 ioctl: will be removed in the near future, to be replaced by
-   VIDIOC_INT_S_AUDIO_ROUTING. */
-struct msp_matrix {
-  int input;
-  int output;
-};
-#define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
-
 /* tuner ioctls */
 
 /* Sets tuner type and its I2C addr */
@@ -209,10 +198,10 @@ struct v4l2_routing {
 };
 
 /* These internal commands should be used to define the inputs and outputs
-   of an audio/video chip. They will replace AUDC_SET_INPUT.
-   The v4l2 API commands VIDIOC_S/G_INPUT, VIDIOC_S/G_OUTPUT,
-   VIDIOC_S/G_AUDIO and VIDIOC_S/G_AUDOUT are meant to be used by the
-   user. Internally these commands should be used to switch inputs/outputs
+   of an audio/video chip. They will replace the v4l2 API commands
+   VIDIOC_S/G_INPUT, VIDIOC_S/G_OUTPUT, VIDIOC_S/G_AUDIO and VIDIOC_S/G_AUDOUT
+   that are meant to be used by the user.
+   The internal commands should be used to switch inputs/outputs
    because only the driver knows how to map a 'Television' input to the precise
    input/output routing of an A/D converter, or a DSP, or a video digitizer.
    These four commands should only be sent directly to an i2c device, they
index d90dec5484ee367966694c37d7db07e964282c95..fff3fd0fbf94056248c1921a0fc057512b7b7c26 100644 (file)
@@ -1,15 +1,20 @@
 /*
  *
  * generic helper functions for video4linux capture buffers, to handle
- * memory management and PCI DMA.  Right now bttv + saa7134 use it.
+ * memory management and PCI DMA.
+ * Right now, bttv, saa7134, saa7146 and cx88 use it.
  *
  * The functions expect the hardware being able to scatter gatter
  * (i.e. the buffers are not linear in physical memory, but fragmented
  * into PAGE_SIZE chunks).  They also assume the driver does not need
- * to touch the video data (thus it is probably not useful for USB as
- * data often must be uncompressed by the drivers).
+ * to touch the video data.
+ *
+ * device specific map/unmap/sync stuff now are mapped as file operations
+ * to allow its usage by USB and virtual devices.
  *
  * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ * (c) 2006 Ted Walther and John Sokol
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,6 +43,9 @@ struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
 struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages,
                                         int offset);
 
+struct videobuf_buffer;
+struct videobuf_queue;
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -49,7 +57,7 @@ struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages,
  *     pointer + length.  The kernel version just wants the size and
  *     does memory allocation too using vmalloc_32().
  *
- * videobuf_dma_pci_*()
+ * videobuf_dma_*()
  *     see Documentation/DMA-mapping.txt, these functions to
  *     basically the same.  The map function does also build a
  *     scatterlist for the buffer (and unmap frees it ...)
@@ -86,12 +94,18 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
                             int nr_pages);
 int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
                              dma_addr_t addr, int nr_pages);
-int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma);
-int videobuf_dma_pci_sync(struct pci_dev *dev,
-                         struct videobuf_dmabuf *dma);
-int videobuf_dma_pci_unmap(struct pci_dev *dev, struct videobuf_dmabuf *dma);
 int videobuf_dma_free(struct videobuf_dmabuf *dma);
 
+int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
+int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
+int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
+
+       /*FIXME: these variants are used only on *-alsa code, where videobuf is
+        * used without queue
+        */
+int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma);
+int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma);
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -115,9 +129,6 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma);
  *
  */
 
-struct videobuf_buffer;
-struct videobuf_queue;
-
 struct videobuf_mapping {
        unsigned int count;
        unsigned long start;
@@ -164,6 +175,10 @@ struct videobuf_buffer {
        struct timeval          ts;
 };
 
+typedef int (vb_map_sg_t)(void *dev,struct scatterlist *sglist,int nr_pages,
+                                       int direction);
+
+
 struct videobuf_queue_ops {
        int (*buf_setup)(struct videobuf_queue *q,
                         unsigned int *count, unsigned int *size);
@@ -174,12 +189,20 @@ struct videobuf_queue_ops {
                          struct videobuf_buffer *vb);
        void (*buf_release)(struct videobuf_queue *q,
                            struct videobuf_buffer *vb);
+
+       /* Helper operations - device dependent.
+        * If null, videobuf_init defaults all to PCI handling
+        */
+
+       vb_map_sg_t     *vb_map_sg;
+       vb_map_sg_t     *vb_dma_sync_sg;
+       vb_map_sg_t     *vb_unmap_sg;
 };
 
 struct videobuf_queue {
        struct mutex               lock;
        spinlock_t                 *irqlock;
-       struct pci_dev             *pci;
+       void                       *dev; /* on pci, points to struct pci_dev */
 
        enum v4l2_buf_type         type;
        unsigned int               inputs; /* for V4L2_BUF_FLAG_INPUT */
@@ -204,12 +227,15 @@ struct videobuf_queue {
 
 void* videobuf_alloc(unsigned int size);
 int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
-int videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb,
-                   struct v4l2_framebuffer *fbuf);
+int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
+               struct v4l2_framebuffer *fbuf);
+
+/* Maps fops to PCI stuff */
+void videobuf_queue_pci(struct videobuf_queue* q);
 
 void videobuf_queue_init(struct videobuf_queue *q,
                         struct videobuf_queue_ops *ops,
-                        struct pci_dev *pci,
+                        void *dev,
                         spinlock_t *irqlock,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
diff --git a/include/media/wm8775.h b/include/media/wm8775.h
new file mode 100644 (file)
index 0000000..60739c5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+    wm8775.h - definition for wm8775 inputs and outputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _WM8775_H_
+#define _WM8775_H_
+
+/* The WM8775 has 4 inputs and one output. Zero or more inputs
+   are multiplexed together to the output. Hence there are
+   16 combinations.
+   If only one input is active (the normal case) then the
+   input values 1, 2, 4 or 8 should be used. */
+
+#define WM8775_AIN1 1
+#define WM8775_AIN2 2
+#define WM8775_AIN3 4
+#define WM8775_AIN4 8
+
+#endif
index 9c04f15090d2b6b6e75060ab56dfb69047ea5db7..98c915abdec8791c409ab811df55cdf50421a9ea 100644 (file)
@@ -110,7 +110,7 @@ extern struct ip_rt_acct *ip_rt_acct;
 struct in_device;
 extern int             ip_rt_init(void);
 extern void            ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
-                                      u32 src, u8 tos, struct net_device *dev);
+                                      u32 src, struct net_device *dev);
 extern void            ip_rt_advice(struct rtable **rp, int advice);
 extern void            rt_cache_flush(int how);
 extern int             __ip_route_output_key(struct rtable **, const struct flowi *flp);
index ec226f31dc2a384ab9e4884d59f6add1195ac37f..2aa73c0ec6c277a674bf535cf7c0063b369d5348 100644 (file)
@@ -210,6 +210,7 @@ struct sock {
        gfp_t                   sk_allocation;
        int                     sk_sndbuf;
        int                     sk_route_caps;
+       int                     sk_rcvlowat;
        unsigned long           sk_flags;
        unsigned long           sk_lingertime;
        /*
@@ -230,7 +231,6 @@ struct sock {
        unsigned short          sk_max_ack_backlog;
        __u32                   sk_priority;
        struct ucred            sk_peercred;
-       int                     sk_rcvlowat;
        long                    sk_rcvtimeo;
        long                    sk_sndtimeo;
        struct sk_filter        *sk_filter;
index 6f4ea808cf74b4ae9e2e47f19da0231e5b07a51a..ac021379ac40abb0b1c7767a69d90ce33d412b88 100644 (file)
 #endif
 
 /* max number of simultaneous board */
-/* warning : make sure module array def's are coherent with PM3_MAX_BOARD */
 #define PM3_MAX_BOARD 4
-#define PM3_MAX_BOARD_MODULE_ARRAY_SHORT "1-4h"
-#define PM3_MAX_BOARD_MODULE_ARRAY_STRING "1-4s"
 
 /* max size of options */
 #define PM3_OPTIONS_SIZE 256
index 1d19fd25204bc2083a002e73c9240b20e95345e4..05951c1d654e25a00d83f97d352cf6b768facdb0 100644 (file)
@@ -470,15 +470,6 @@ config MODULE_FORCE_UNLOAD
          rmmod).  This is mainly for kernel developers and desperate users.
          If unsure, say N.
 
-config OBSOLETE_MODPARM
-       bool
-       default y
-       depends on MODULES
-       help
-         You need this option to use module parameters on modules which
-         have not been converted to the new module parameter system yet.
-         If unsure, say Y.
-
 config MODVERSIONS
        bool "Module versioning support"
        depends on MODULES
index 637344b059813c7554a1acff0af67291b2272ca8..77b934cccefe5526bff1a8234e8dd2fd6cd85dff 100644 (file)
@@ -506,6 +506,7 @@ void __init populate_rootfs(void)
                panic(err);
 #ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start) {
+#ifdef CONFIG_BLK_DEV_RAM
                int fd;
                printk(KERN_INFO "checking if image is initramfs...");
                err = unpack_to_rootfs((char *)initrd_start,
@@ -525,6 +526,15 @@ void __init populate_rootfs(void)
                        sys_close(fd);
                        free_initrd();
                }
+#else
+               printk(KERN_INFO "Unpacking initramfs...");
+               err = unpack_to_rootfs((char *)initrd_start,
+                       initrd_end - initrd_start, 0);
+               if (err)
+                       panic(err);
+               printk(" done\n");
+               free_initrd();
+#endif
        }
 #endif
 }
index 2714e0e7cfecb78c45a3f6a17bc2d1598ab66f42..006dcd547dc2e72bd3280ac31e746d34da1970bf 100644 (file)
@@ -306,8 +306,6 @@ static int __init rdinit_setup(char *str)
 }
 __setup("rdinit=", rdinit_setup);
 
-extern void setup_arch(char **);
-
 #ifndef CONFIG_SMP
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -571,17 +569,23 @@ static void __init do_initcalls(void)
        int count = preempt_count();
 
        for (call = __initcall_start; call < __initcall_end; call++) {
-               char *msg;
+               char *msg = NULL;
+               char msgbuf[40];
+               int result;
 
                if (initcall_debug) {
-                       printk(KERN_DEBUG "Calling initcall 0x%p", *call);
-                       print_fn_descriptor_symbol(": %s()", (unsigned long) *call);
+                       printk("Calling initcall 0x%p", *call);
+                       print_fn_descriptor_symbol(": %s()",
+                                       (unsigned long) *call);
                        printk("\n");
                }
 
-               (*call)();
+               result = (*call)();
 
-               msg = NULL;
+               if (result && (result != -ENODEV || initcall_debug)) {
+                       sprintf(msgbuf, "error code %d", result);
+                       msg = msgbuf;
+               }
                if (preempt_count() != count) {
                        msg = "preemption imbalance";
                        preempt_count() = count;
@@ -591,8 +595,10 @@ static void __init do_initcalls(void)
                        local_irq_enable();
                }
                if (msg) {
-                       printk(KERN_WARNING "error in initcall at 0x%p: "
-                               "returned with %s\n", *call, msg);
+                       printk(KERN_WARNING "initcall at 0x%p", *call);
+                       print_fn_descriptor_symbol(": %s()",
+                                       (unsigned long) *call);
+                       printk(": returned with %s\n", msg);
                }
        }
 
index bfa3c92e16f2b1c5a9971335f6500cb17a6c8a49..1a4d8a40d3f9e120f204b59c060cd3e46232e70f 100644 (file)
@@ -233,3 +233,19 @@ out:
 
      return ret;
 }
+
+int __capable(struct task_struct *t, int cap)
+{
+       if (security_capable(t, cap) == 0) {
+               t->flags |= PF_SUPERPRIV;
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(__capable);
+
+int capable(int cap)
+{
+       return __capable(current, cap);
+}
+EXPORT_SYMBOL(capable);
index 49378738ff5e751fe0c139e994b4cdc3cfa2c32c..2b33f852be3eaf123aa63d530f2d58c5126a19c2 100644 (file)
@@ -1,5 +1,4 @@
 
-obj-y := handle.o manage.o spurious.o
+obj-y := handle.o manage.o spurious.o migration.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
-
index 97d5559997d28d1b4811b5ed5d1b267cc8715a49..6edfcef291e8202eb6173c28d267afa7851cf04e 100644 (file)
@@ -204,10 +204,14 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        p = &desc->action;
        if ((old = *p) != NULL) {
                /* Can't share interrupts unless both agree to */
-               if (!(old->flags & new->flags & SA_SHIRQ)) {
-                       spin_unlock_irqrestore(&desc->lock,flags);
-                       return -EBUSY;
-               }
+               if (!(old->flags & new->flags & SA_SHIRQ))
+                       goto mismatch;
+
+#if defined(ARCH_HAS_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
+               /* All handlers must agree on per-cpuness */
+               if ((old->flags & IRQ_PER_CPU) != (new->flags & IRQ_PER_CPU))
+                       goto mismatch;
+#endif
 
                /* add new interrupt at end of irq queue */
                do {
@@ -218,7 +222,10 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        }
 
        *p = new;
-
+#if defined(ARCH_HAS_IRQ_PER_CPU) && defined(SA_PERCPU_IRQ)
+       if (new->flags & SA_PERCPU_IRQ)
+               desc->status |= IRQ_PER_CPU;
+#endif
        if (!shared) {
                desc->depth = 0;
                desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
@@ -236,6 +243,12 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        register_handler_proc(irq, new);
 
        return 0;
+
+mismatch:
+       spin_unlock_irqrestore(&desc->lock, flags);
+       printk(KERN_ERR "%s: irq handler mismatch\n", __FUNCTION__);
+       dump_stack();
+       return -EBUSY;
 }
 
 /**
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
new file mode 100644 (file)
index 0000000..52a8655
--- /dev/null
@@ -0,0 +1,65 @@
+#include <linux/irq.h>
+
+#if defined(CONFIG_GENERIC_PENDING_IRQ)
+
+void set_pending_irq(unsigned int irq, cpumask_t mask)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->move_irq = 1;
+       pending_irq_cpumask[irq] = mask;
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+void move_native_irq(int irq)
+{
+       cpumask_t tmp;
+       irq_desc_t *desc = irq_descp(irq);
+
+       if (likely(!desc->move_irq))
+               return;
+
+       /*
+        * Paranoia: cpu-local interrupts shouldn't be calling in here anyway.
+        */
+       if (CHECK_IRQ_PER_CPU(desc->status)) {
+               WARN_ON(1);
+               return;
+       }
+
+       desc->move_irq = 0;
+
+       if (likely(cpus_empty(pending_irq_cpumask[irq])))
+               return;
+
+       if (!desc->handler->set_affinity)
+               return;
+
+       assert_spin_locked(&desc->lock);
+
+       cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
+
+       /*
+        * If there was a valid mask to work with, please
+        * do the disable, re-program, enable sequence.
+        * This is *not* particularly important for level triggered
+        * but in a edge trigger case, we might be setting rte
+        * when an active trigger is comming in. This could
+        * cause some ioapics to mal-function.
+        * Being paranoid i guess!
+        */
+       if (unlikely(!cpus_empty(tmp))) {
+               if (likely(!(desc->status & IRQ_DISABLED)))
+                       desc->handler->disable(irq);
+
+               desc->handler->set_affinity(irq,tmp);
+
+               if (likely(!(desc->status & IRQ_DISABLED)))
+                       desc->handler->enable(irq);
+       }
+       cpus_clear(pending_irq_cpumask[irq]);
+}
+
+#endif
index 379be2f8c84c33445b9cea549fe2c7215d3d6cc4..680e6b70c8726f00d6a5d4dc3888fa5218b498fe 100644 (file)
@@ -143,6 +143,60 @@ int it_real_fn(void *data)
        return HRTIMER_NORESTART;
 }
 
+/*
+ * We do not care about correctness. We just sanitize the values so
+ * the ktime_t operations which expect normalized values do not
+ * break. This converts negative values to long timeouts similar to
+ * the code in kernel versions < 2.6.16
+ *
+ * Print a limited number of warning messages when an invalid timeval
+ * is detected.
+ */
+static void fixup_timeval(struct timeval *tv, int interval)
+{
+       static int warnlimit = 10;
+       unsigned long tmp;
+
+       if (warnlimit > 0) {
+               warnlimit--;
+               printk(KERN_WARNING
+                      "setitimer: %s (pid = %d) provided "
+                      "invalid timeval %s: tv_sec = %ld tv_usec = %ld\n",
+                      current->comm, current->pid,
+                      interval ? "it_interval" : "it_value",
+                      tv->tv_sec, (long) tv->tv_usec);
+       }
+
+       tmp = tv->tv_usec;
+       if (tmp >= USEC_PER_SEC) {
+               tv->tv_usec = tmp % USEC_PER_SEC;
+               tv->tv_sec += tmp / USEC_PER_SEC;
+       }
+
+       tmp = tv->tv_sec;
+       if (tmp > LONG_MAX)
+               tv->tv_sec = LONG_MAX;
+}
+
+/*
+ * Returns true if the timeval is in canonical form
+ */
+#define timeval_valid(t) \
+       (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
+
+/*
+ * Check for invalid timevals, sanitize them and print a limited
+ * number of warnings.
+ */
+static void check_itimerval(struct itimerval *value) {
+
+       if (unlikely(!timeval_valid(&value->it_value)))
+               fixup_timeval(&value->it_value, 0);
+
+       if (unlikely(!timeval_valid(&value->it_interval)))
+               fixup_timeval(&value->it_interval, 1);
+}
+
 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 {
        struct task_struct *tsk = current;
@@ -150,6 +204,18 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
        ktime_t expires;
        cputime_t cval, cinterval, nval, ninterval;
 
+       /*
+        * Validate the timevals in value.
+        *
+        * Note: Although the spec requires that invalid values shall
+        * return -EINVAL, we just fixup the value and print a limited
+        * number of warnings in order not to break users of this
+        * historical misfeature.
+        *
+        * Scheduled for replacement in March 2007
+        */
+       check_itimerval(value);
+
        switch (which) {
        case ITIMER_REAL:
 again:
@@ -226,6 +292,43 @@ again:
        return 0;
 }
 
+/**
+ * alarm_setitimer - set alarm in seconds
+ *
+ * @seconds:   number of seconds until alarm
+ *             0 disables the alarm
+ *
+ * Returns the remaining time in seconds of a pending timer or 0 when
+ * the timer is not active.
+ *
+ * On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid
+ * negative timeval settings which would cause immediate expiry.
+ */
+unsigned int alarm_setitimer(unsigned int seconds)
+{
+       struct itimerval it_new, it_old;
+
+#if BITS_PER_LONG < 64
+       if (seconds > INT_MAX)
+               seconds = INT_MAX;
+#endif
+       it_new.it_value.tv_sec = seconds;
+       it_new.it_value.tv_usec = 0;
+       it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+
+       do_setitimer(ITIMER_REAL, &it_new, &it_old);
+
+       /*
+        * We can't return 0 if we have an alarm pending ...  And we'd
+        * better return too much than too little anyway
+        */
+       if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) ||
+             it_old.it_value.tv_usec >= 500000)
+               it_old.it_value.tv_sec++;
+
+       return it_old.it_value.tv_sec;
+}
+
 asmlinkage long sys_setitimer(int which,
                              struct itimerval __user *value,
                              struct itimerval __user *ovalue)
index 6a5373868a985ea98707d4aefed624f011d6c65f..c5f3c6613b6d77dd21d6a0bfcedfbe44d624f802 100644 (file)
@@ -115,7 +115,9 @@ static void keventd_create_kthread(void *_create)
                create->result = ERR_PTR(pid);
        } else {
                wait_for_completion(&create->started);
+               read_lock(&tasklist_lock);
                create->result = find_task_by_pid(pid);
+               read_unlock(&tasklist_lock);
        }
        complete(&create->done);
 }
index 54623c714bba38e0f2729a7241445ae8ce46e0d5..ddfe45ac2fd1d9b8ec0cacc908841f5c79320c48 100644 (file)
@@ -233,24 +233,6 @@ static unsigned long __find_symbol(const char *name,
        return 0;
 }
 
-/* Find a symbol in this elf symbol table */
-static unsigned long find_local_symbol(Elf_Shdr *sechdrs,
-                                      unsigned int symindex,
-                                      const char *strtab,
-                                      const char *name)
-{
-       unsigned int i;
-       Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
-
-       /* Search (defined) internal symbols first. */
-       for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) {
-               if (sym[i].st_shndx != SHN_UNDEF
-                   && strcmp(name, strtab + sym[i].st_name) == 0)
-                       return sym[i].st_value;
-       }
-       return 0;
-}
-
 /* Search for module by name: must hold module_mutex. */
 static struct module *find_module(const char *name)
 {
@@ -785,139 +767,6 @@ static struct module_attribute *modinfo_attrs[] = {
        NULL,
 };
 
-#ifdef CONFIG_OBSOLETE_MODPARM
-/* Bounds checking done below */
-static int obsparm_copy_string(const char *val, struct kernel_param *kp)
-{
-       strcpy(kp->arg, val);
-       return 0;
-}
-
-static int set_obsolete(const char *val, struct kernel_param *kp)
-{
-       unsigned int min, max;
-       unsigned int size, maxsize;
-       int dummy;
-       char *endp;
-       const char *p;
-       struct obsolete_modparm *obsparm = kp->arg;
-
-       if (!val) {
-               printk(KERN_ERR "Parameter %s needs an argument\n", kp->name);
-               return -EINVAL;
-       }
-
-       /* type is: [min[-max]]{b,h,i,l,s} */
-       p = obsparm->type;
-       min = simple_strtol(p, &endp, 10);
-       if (endp == obsparm->type)
-               min = max = 1;
-       else if (*endp == '-') {
-               p = endp+1;
-               max = simple_strtol(p, &endp, 10);
-       } else
-               max = min;
-       switch (*endp) {
-       case 'b':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  1, param_set_byte, &dummy);
-       case 'h':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(short), param_set_short, &dummy);
-       case 'i':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(int), param_set_int, &dummy);
-       case 'l':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(long), param_set_long, &dummy);
-       case 's':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(char *), param_set_charp, &dummy);
-
-       case 'c':
-               /* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars,
-                  and the decl is "char xxx[5][50];" */
-               p = endp+1;
-               maxsize = simple_strtol(p, &endp, 10);
-               /* We check lengths here (yes, this is a hack). */
-               p = val;
-               while (p[size = strcspn(p, ",")]) {
-                       if (size >= maxsize) 
-                               goto oversize;
-                       p += size+1;
-               }
-               if (size >= maxsize) 
-                       goto oversize;
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  maxsize, obsparm_copy_string, &dummy);
-       }
-       printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type);
-       return -EINVAL;
- oversize:
-       printk(KERN_ERR
-              "Parameter %s doesn't fit in %u chars.\n", kp->name, maxsize);
-       return -EINVAL;
-}
-
-static int obsolete_params(const char *name,
-                          char *args,
-                          struct obsolete_modparm obsparm[],
-                          unsigned int num,
-                          Elf_Shdr *sechdrs,
-                          unsigned int symindex,
-                          const char *strtab)
-{
-       struct kernel_param *kp;
-       unsigned int i;
-       int ret;
-
-       kp = kmalloc(sizeof(kp[0]) * num, GFP_KERNEL);
-       if (!kp)
-               return -ENOMEM;
-
-       for (i = 0; i < num; i++) {
-               char sym_name[128 + sizeof(MODULE_SYMBOL_PREFIX)];
-
-               snprintf(sym_name, sizeof(sym_name), "%s%s",
-                        MODULE_SYMBOL_PREFIX, obsparm[i].name);
-
-               kp[i].name = obsparm[i].name;
-               kp[i].perm = 000;
-               kp[i].set = set_obsolete;
-               kp[i].get = NULL;
-               obsparm[i].addr
-                       = (void *)find_local_symbol(sechdrs, symindex, strtab,
-                                                   sym_name);
-               if (!obsparm[i].addr) {
-                       printk("%s: falsely claims to have parameter %s\n",
-                              name, obsparm[i].name);
-                       ret = -EINVAL;
-                       goto out;
-               }
-               kp[i].arg = &obsparm[i];
-       }
-
-       ret = parse_args(name, args, kp, num, NULL);
- out:
-       kfree(kp);
-       return ret;
-}
-#else
-static int obsolete_params(const char *name,
-                          char *args,
-                          struct obsolete_modparm obsparm[],
-                          unsigned int num,
-                          Elf_Shdr *sechdrs,
-                          unsigned int symindex,
-                          const char *strtab)
-{
-       if (num != 0)
-               printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
-                      name);
-       return 0;
-}
-#endif /* CONFIG_OBSOLETE_MODPARM */
-
 static const char vermagic[] = VERMAGIC_STRING;
 
 #ifdef CONFIG_MODVERSIONS
@@ -1874,27 +1723,17 @@ static struct module *load_module(void __user *umod,
        set_fs(old_fs);
 
        mod->args = args;
-       if (obsparmindex) {
-               err = obsolete_params(mod->name, mod->args,
-                                     (struct obsolete_modparm *)
-                                     sechdrs[obsparmindex].sh_addr,
-                                     sechdrs[obsparmindex].sh_size
-                                     / sizeof(struct obsolete_modparm),
-                                     sechdrs, symindex,
-                                     (char *)sechdrs[strindex].sh_addr);
-               if (setupindex)
-                       printk(KERN_WARNING "%s: Ignoring new-style "
-                              "parameters in presence of obsolete ones\n",
-                              mod->name);
-       } else {
-               /* Size of section 0 is 0, so this works well if no params */
-               err = parse_args(mod->name, mod->args,
-                                (struct kernel_param *)
-                                sechdrs[setupindex].sh_addr,
-                                sechdrs[setupindex].sh_size
-                                / sizeof(struct kernel_param),
-                                NULL);
-       }
+       if (obsparmindex)
+               printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
+                      mod->name);
+
+       /* Size of section 0 is 0, so this works well if no params */
+       err = parse_args(mod->name, mod->args,
+                        (struct kernel_param *)
+                        sechdrs[setupindex].sh_addr,
+                        sechdrs[setupindex].sh_size
+                        / sizeof(struct kernel_param),
+                        NULL);
        if (err < 0)
                goto arch_cleanup;
 
index a29150582310e05e5bedd83f5e216610c9e69495..9de637a5c8bc920df2875910d29aba8dc0b4e3bb 100644 (file)
@@ -265,12 +265,12 @@ int param_get_invbool(char *buffer, struct kernel_param *kp)
 }
 
 /* We cheat here and temporarily mangle the string. */
-int param_array(const char *name,
-               const char *val,
-               unsigned int min, unsigned int max,
-               void *elem, int elemsize,
-               int (*set)(const char *, struct kernel_param *kp),
-               int *num)
+static int param_array(const char *name,
+                      const char *val,
+                      unsigned int min, unsigned int max,
+                      void *elem, int elemsize,
+                      int (*set)(const char *, struct kernel_param *kp),
+                      int *num)
 {
        int ret;
        struct kernel_param kp;
index 911fc62b822546d0e1b05dddb0c2d8bdc771c056..5957312b2d68f56a875def730ffe27682bcea52a 100644 (file)
@@ -49,9 +49,7 @@ void enable_nonboot_cpus(void)
 
        printk("Thawing cpus ...\n");
        for_each_cpu_mask(cpu, frozen_cpus) {
-               error = smp_prepare_cpu(cpu);
-               if (!error)
-                       error = cpu_up(cpu);
+               error = cpu_up(cpu);
                if (!error) {
                        printk("CPU%d is up\n", cpu);
                        continue;
index 9a1fa8894b95f54c7160dd351c7f7c8f55f725c5..b4b362b5baf5a6ccd101f13ab39f3c5043352b33 100644 (file)
@@ -54,15 +54,15 @@ static int verbose;         /* Print more debug info. */
 static int test_no_idle_hz;    /* Test RCU's support for tickless idle CPUs. */
 static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
 
-MODULE_PARM(nreaders, "i");
+module_param(nreaders, int, 0);
 MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-MODULE_PARM(stat_interval, "i");
+module_param(stat_interval, int, 0);
 MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-MODULE_PARM(verbose, "i");
+module_param(verbose, bool, 0);
 MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-MODULE_PARM(test_no_idle_hz, "i");
+module_param(test_no_idle_hz, bool, 0);
 MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-MODULE_PARM(shuffle_interval, "i");
+module_param(shuffle_interval, int, 0);
 MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
 #define TORTURE_FLAG "rcutorture: "
 #define PRINTK_STRING(s) \
index dd9524fa649a846be83fd4c9c6d59d322f8af53e..d9b3d5847ed8719c8fc57b410ddafe817adddee6 100644 (file)
@@ -118,6 +118,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                        printk("watchdog for %i failed\n", hotcpu);
                        return NOTIFY_BAD;
                }
+               per_cpu(touch_timestamp, hotcpu) = jiffies;
                per_cpu(watchdog_task, hotcpu) = p;
                kthread_bind(p, hotcpu);
                break;
index 19d058be49d496252534b95bd241512d24aed271..38bc73ede2baddef2e3c1068d26cd6e8b4e4ad24 100644 (file)
@@ -224,18 +224,6 @@ int unregister_reboot_notifier(struct notifier_block * nb)
 
 EXPORT_SYMBOL(unregister_reboot_notifier);
 
-#ifndef CONFIG_SECURITY
-int capable(int cap)
-{
-        if (cap_raised(current->cap_effective, cap)) {
-              current->flags |= PF_SUPERPRIV;
-              return 1;
-        }
-        return 0;
-}
-EXPORT_SYMBOL(capable);
-#endif
-
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
        int no_nice;
@@ -1375,7 +1363,7 @@ static void groups_sort(struct group_info *group_info)
 /* a simple bsearch */
 int groups_search(struct group_info *group_info, gid_t grp)
 {
-       int left, right;
+       unsigned int left, right;
 
        if (!group_info)
                return 0;
@@ -1383,7 +1371,7 @@ int groups_search(struct group_info *group_info, gid_t grp)
        left = 0;
        right = group_info->ngroups;
        while (left < right) {
-               int mid = (left+right)/2;
+               unsigned int mid = (left+right)/2;
                int cmp = grp - GROUP_AT(group_info, mid);
                if (cmp > 0)
                        left = mid + 1;
@@ -1433,7 +1421,6 @@ asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
                return -EINVAL;
 
        /* no need to grab task_lock here; it cannot change */
-       get_group_info(current->group_info);
        i = current->group_info->ngroups;
        if (gidsetsize) {
                if (i > gidsetsize) {
@@ -1446,7 +1433,6 @@ asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
                }
        }
 out:
-       put_group_info(current->group_info);
        return i;
 }
 
@@ -1487,9 +1473,7 @@ int in_group_p(gid_t grp)
 {
        int retval = 1;
        if (grp != current->fsgid) {
-               get_group_info(current->group_info);
                retval = groups_search(current->group_info, grp);
-               put_group_info(current->group_info);
        }
        return retval;
 }
@@ -1500,9 +1484,7 @@ int in_egroup_p(gid_t grp)
 {
        int retval = 1;
        if (grp != current->egid) {
-               get_group_info(current->group_info);
                retval = groups_search(current->group_info, grp);
-               put_group_info(current->group_info);
        }
        return retval;
 }
index 804539165d8b1aea0ea0dac3631377d7ae107f89..e00a97b77241245cd008f6f843ee6f300e3f5578 100644 (file)
@@ -202,24 +202,6 @@ asmlinkage long sys_settimeofday(struct timeval __user *tv,
        return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
 }
 
-long pps_offset;               /* pps time offset (us) */
-long pps_jitter = MAXTIME;     /* time dispersion (jitter) (us) */
-
-long pps_freq;                 /* frequency offset (scaled ppm) */
-long pps_stabil = MAXFREQ;     /* frequency dispersion (scaled ppm) */
-
-long pps_valid = PPS_VALID;    /* pps signal watchdog counter */
-
-int pps_shift = PPS_SHIFT;     /* interval duration (s) (shift) */
-
-long pps_jitcnt;               /* jitter limit exceeded */
-long pps_calcnt;               /* calibration intervals */
-long pps_errcnt;               /* calibration errors */
-long pps_stbcnt;               /* stability limit exceeded */
-
-/* hook for a loadable hardpps kernel module */
-void (*hardpps_ptr)(struct timeval *);
-
 /* we call this to notify the arch when the clock is being
  * controlled.  If no such arch routine, do nothing.
  */
@@ -279,7 +261,7 @@ int do_adjtimex(struct timex *txc)
                    result = -EINVAL;
                    goto leave;
                }
-               time_freq = txc->freq - pps_freq;
+               time_freq = txc->freq;
            }
 
            if (txc->modes & ADJ_MAXERROR) {
@@ -312,10 +294,8 @@ int do_adjtimex(struct timex *txc)
                    if ((time_next_adjust = txc->offset) == 0)
                         time_adjust = 0;
                }
-               else if ( time_status & (STA_PLL | STA_PPSTIME) ) {
-                   ltemp = (time_status & (STA_PPSTIME | STA_PPSSIGNAL)) ==
-                           (STA_PPSTIME | STA_PPSSIGNAL) ?
-                           pps_offset : txc->offset;
+               else if (time_status & STA_PLL) {
+                   ltemp = txc->offset;
 
                    /*
                     * Scale the phase adjustment and
@@ -356,23 +336,14 @@ int do_adjtimex(struct timex *txc)
                    }
                    time_freq = min(time_freq, time_tolerance);
                    time_freq = max(time_freq, -time_tolerance);
-               } /* STA_PLL || STA_PPSTIME */
+               } /* STA_PLL */
            } /* txc->modes & ADJ_OFFSET */
            if (txc->modes & ADJ_TICK) {
                tick_usec = txc->tick;
                tick_nsec = TICK_USEC_TO_NSEC(tick_usec);
            }
        } /* txc->modes */
-leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
-           || ((time_status & (STA_PPSFREQ|STA_PPSTIME)) != 0
-               && (time_status & STA_PPSSIGNAL) == 0)
-           /* p. 24, (b) */
-           || ((time_status & (STA_PPSTIME|STA_PPSJITTER))
-               == (STA_PPSTIME|STA_PPSJITTER))
-           /* p. 24, (c) */
-           || ((time_status & STA_PPSFREQ) != 0
-               && (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0))
-           /* p. 24, (d) */
+leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
                result = TIME_ERROR;
        
        if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
@@ -380,7 +351,7 @@ leave:      if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
        else {
            txc->offset = shift_right(time_offset, SHIFT_UPDATE);
        }
-       txc->freq          = time_freq + pps_freq;
+       txc->freq          = time_freq;
        txc->maxerror      = time_maxerror;
        txc->esterror      = time_esterror;
        txc->status        = time_status;
@@ -388,14 +359,16 @@ leave:    if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
        txc->precision     = time_precision;
        txc->tolerance     = time_tolerance;
        txc->tick          = tick_usec;
-       txc->ppsfreq       = pps_freq;
-       txc->jitter        = pps_jitter >> PPS_AVG;
-       txc->shift         = pps_shift;
-       txc->stabil        = pps_stabil;
-       txc->jitcnt        = pps_jitcnt;
-       txc->calcnt        = pps_calcnt;
-       txc->errcnt        = pps_errcnt;
-       txc->stbcnt        = pps_stbcnt;
+
+       /* PPS is not implemented, so these are zero */
+       txc->ppsfreq       = 0;
+       txc->jitter        = 0;
+       txc->shift         = 0;
+       txc->stabil        = 0;
+       txc->jitcnt        = 0;
+       txc->calcnt        = 0;
+       txc->errcnt        = 0;
+       txc->stbcnt        = 0;
        write_sequnlock_irq(&xtime_lock);
        do_gettimeofday(&txc->time);
        notify_arch_cmos_timer();
index 17d956cebcb9dcc7207f637bc512a4ad2d3002e8..ab189dd187cb870f0aca3a2a7ba0fbb7988d421d 100644 (file)
@@ -697,18 +697,9 @@ static void second_overflow(void)
 
        /*
         * Compute the frequency estimate and additional phase adjustment due
-        * to frequency error for the next second. When the PPS signal is
-        * engaged, gnaw on the watchdog counter and update the frequency
-        * computed by the pll and the PPS signal.
+        * to frequency error for the next second.
         */
-       pps_valid++;
-       if (pps_valid == PPS_VALID) {   /* PPS signal lost */
-               pps_jitter = MAXTIME;
-               pps_stabil = MAXFREQ;
-               time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
-                               STA_PPSWANDER | STA_PPSERROR);
-       }
-       ltemp = time_freq + pps_freq;
+       ltemp = time_freq;
        time_adj += shift_right(ltemp,(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE));
 
 #if HZ == 100
@@ -956,19 +947,7 @@ void do_timer(struct pt_regs *regs)
  */
 asmlinkage unsigned long sys_alarm(unsigned int seconds)
 {
-       struct itimerval it_new, it_old;
-       unsigned int oldalarm;
-
-       it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
-       it_new.it_value.tv_sec = seconds;
-       it_new.it_value.tv_usec = 0;
-       do_setitimer(ITIMER_REAL, &it_new, &it_old);
-       oldalarm = it_old.it_value.tv_sec;
-       /* ehhh.. We can't return 0 if we have an alarm pending.. */
-       /* And we'd better return too much than too little anyway */
-       if ((!oldalarm && it_old.it_value.tv_usec) || it_old.it_value.tv_usec >= 500000)
-               oldalarm++;
-       return oldalarm;
+       return alarm_setitimer(seconds);
 }
 
 #endif
index f2618e1c2b934ed7c67956ec5597753ca198a4d1..0bda3c5259f739683b35b7288da445cf53f30acc 100644 (file)
@@ -78,13 +78,17 @@ config SCHEDSTATS
          this adds.
 
 config DEBUG_SLAB
-       bool "Debug memory allocations"
+       bool "Debug slab memory allocations"
        depends on DEBUG_KERNEL && SLAB
        help
          Say Y here to have the kernel do limited verification on memory
          allocation as well as poisoning memory on free to catch use of freed
          memory. This can make kmalloc/kfree-intensive workloads much slower.
 
+config DEBUG_SLAB_LEAK
+       bool "Memory leak debugging"
+       depends on DEBUG_SLAB
+
 config DEBUG_PREEMPT
        bool "Debug preemptible kernel"
        depends on DEBUG_KERNEL && PREEMPT
index 648b2c1242fd9066aae0aa966914ee0f47fbce04..f827e3c24ec0da771bd72178198df85da9612c15 100644 (file)
@@ -7,6 +7,8 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
         idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
         sha1.o
 
+lib-$(CONFIG_SMP) += cpumask.o
+
 lib-y  += kobject.o kref.o kobject_uevent.o klist.o
 
 obj-y += sort.o parser.o halfmd4.o iomap_copy.o
diff --git a/lib/cpumask.c b/lib/cpumask.c
new file mode 100644 (file)
index 0000000..3a67dc5
--- /dev/null
@@ -0,0 +1,45 @@
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+
+int __first_cpu(const cpumask_t *srcp)
+{
+       return min_t(int, NR_CPUS, find_first_bit(srcp->bits, NR_CPUS));
+}
+EXPORT_SYMBOL(__first_cpu);
+
+int __next_cpu(int n, const cpumask_t *srcp)
+{
+       return min_t(int, NR_CPUS, find_next_bit(srcp->bits, NR_CPUS, n+1));
+}
+EXPORT_SYMBOL(__next_cpu);
+
+/*
+ * Find the highest possible smp_processor_id()
+ *
+ * Note: if we're prepared to assume that cpu_possible_map never changes
+ * (reasonable) then this function should cache its return value.
+ */
+int highest_possible_processor_id(void)
+{
+       unsigned int cpu;
+       unsigned highest = 0;
+
+       for_each_cpu_mask(cpu, cpu_possible_map)
+               highest = cpu;
+       return highest;
+}
+EXPORT_SYMBOL(highest_possible_processor_id);
+
+int __any_online_cpu(const cpumask_t *mask)
+{
+       int cpu;
+
+       for_each_cpu_mask(cpu, *mask) {
+               if (cpu_online(cpu))
+                       break;
+       }
+       return cpu;
+}
+EXPORT_SYMBOL(__any_online_cpu);
index 1e5b17dc7e3d5c6da19bdb2376e7a0a120cbc722..7097bb239e406b2ccca5772cb9516e852498f9ef 100644 (file)
@@ -37,7 +37,6 @@
 #else
 #define RADIX_TREE_MAP_SHIFT   3       /* For more stressful testing */
 #endif
-#define RADIX_TREE_TAGS                2
 
 #define RADIX_TREE_MAP_SIZE    (1UL << RADIX_TREE_MAP_SHIFT)
 #define RADIX_TREE_MAP_MASK    (RADIX_TREE_MAP_SIZE-1)
@@ -48,7 +47,7 @@
 struct radix_tree_node {
        unsigned int    count;
        void            *slots[RADIX_TREE_MAP_SIZE];
-       unsigned long   tags[RADIX_TREE_TAGS][RADIX_TREE_TAG_LONGS];
+       unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
 };
 
 struct radix_tree_path {
@@ -135,17 +134,20 @@ out:
        return ret;
 }
 
-static inline void tag_set(struct radix_tree_node *node, int tag, int offset)
+static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
+               int offset)
 {
        __set_bit(offset, node->tags[tag]);
 }
 
-static inline void tag_clear(struct radix_tree_node *node, int tag, int offset)
+static inline void tag_clear(struct radix_tree_node *node, unsigned int tag,
+               int offset)
 {
        __clear_bit(offset, node->tags[tag]);
 }
 
-static inline int tag_get(struct radix_tree_node *node, int tag, int offset)
+static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
+               int offset)
 {
        return test_bit(offset, node->tags[tag]);
 }
@@ -154,7 +156,7 @@ static inline int tag_get(struct radix_tree_node *node, int tag, int offset)
  * Returns 1 if any slot in the node has this tag set.
  * Otherwise returns 0.
  */
-static inline int any_tag_set(struct radix_tree_node *node, int tag)
+static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag)
 {
        int idx;
        for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
@@ -180,7 +182,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
 {
        struct radix_tree_node *node;
        unsigned int height;
-       char tags[RADIX_TREE_TAGS];
+       char tags[RADIX_TREE_MAX_TAGS];
        int tag;
 
        /* Figure out what the height should be.  */
@@ -197,7 +199,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
         * Prepare the tag status of the top-level node for propagation
         * into the newly-pushed top-level node(s)
         */
-       for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+       for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
                tags[tag] = 0;
                if (any_tag_set(root->rnode, tag))
                        tags[tag] = 1;
@@ -211,7 +213,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                node->slots[0] = root->rnode;
 
                /* Propagate the aggregated tag info into the new root */
-               for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+               for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
                        if (tags[tag])
                                tag_set(node, tag, 0);
                }
@@ -349,14 +351,15 @@ EXPORT_SYMBOL(radix_tree_lookup);
  *     @index:         index key
  *     @tag:           tag index
  *
- *     Set the search tag corresponging to @index in the radix tree.  From
+ *     Set the search tag (which must be < RADIX_TREE_MAX_TAGS)
+ *     corresponding to @index in the radix tree.  From
  *     the root all the way down to the leaf node.
  *
  *     Returns the address of the tagged item.   Setting a tag on a not-present
  *     item is a bug.
  */
 void *radix_tree_tag_set(struct radix_tree_root *root,
-                       unsigned long index, int tag)
+                       unsigned long index, unsigned int tag)
 {
        unsigned int height, shift;
        struct radix_tree_node *slot;
@@ -390,7 +393,8 @@ EXPORT_SYMBOL(radix_tree_tag_set);
  *     @index:         index key
  *     @tag:           tag index
  *
- *     Clear the search tag corresponging to @index in the radix tree.  If
+ *     Clear the search tag (which must be < RADIX_TREE_MAX_TAGS)
+ *     corresponding to @index in the radix tree.  If
  *     this causes the leaf node to have no tags set then clear the tag in the
  *     next-to-leaf node, etc.
  *
@@ -398,7 +402,7 @@ EXPORT_SYMBOL(radix_tree_tag_set);
  *     has the same return value and semantics as radix_tree_lookup().
  */
 void *radix_tree_tag_clear(struct radix_tree_root *root,
-                       unsigned long index, int tag)
+                       unsigned long index, unsigned int tag)
 {
        struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
        struct radix_tree_node *slot;
@@ -450,7 +454,7 @@ EXPORT_SYMBOL(radix_tree_tag_clear);
  * radix_tree_tag_get - get a tag on a radix tree node
  * @root:              radix tree root
  * @index:             index key
- * @tag:               tag index
+ * @tag:               tag index (< RADIX_TREE_MAX_TAGS)
  *
  * Return values:
  *
@@ -459,7 +463,7 @@ EXPORT_SYMBOL(radix_tree_tag_clear);
  * -1: tag present, unset
  */
 int radix_tree_tag_get(struct radix_tree_root *root,
-                       unsigned long index, int tag)
+                       unsigned long index, unsigned int tag)
 {
        unsigned int height, shift;
        struct radix_tree_node *slot;
@@ -592,7 +596,7 @@ EXPORT_SYMBOL(radix_tree_gang_lookup);
  */
 static unsigned int
 __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index,
-       unsigned int max_items, unsigned long *next_index, int tag)
+       unsigned int max_items, unsigned long *next_index, unsigned int tag)
 {
        unsigned int nr_found = 0;
        unsigned int shift;
@@ -646,7 +650,7 @@ out:
  *     @results:       where the results of the lookup are placed
  *     @first_index:   start the lookup from this key
  *     @max_items:     place up to this many items at *results
- *     @tag:           the tag index
+ *     @tag:           the tag index (< RADIX_TREE_MAX_TAGS)
  *
  *     Performs an index-ascending scan of the tree for present items which
  *     have the tag indexed by @tag set.  Places the items at *@results and
@@ -654,7 +658,8 @@ out:
  */
 unsigned int
 radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
-               unsigned long first_index, unsigned int max_items, int tag)
+               unsigned long first_index, unsigned int max_items,
+               unsigned int tag)
 {
        const unsigned long max_index = radix_tree_maxindex(root->height);
        unsigned long cur_index = first_index;
@@ -716,7 +721,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
        struct radix_tree_node *slot;
        unsigned int height, shift;
        void *ret = NULL;
-       char tags[RADIX_TREE_TAGS];
+       char tags[RADIX_TREE_MAX_TAGS];
        int nr_cleared_tags;
        int tag;
        int offset;
@@ -751,7 +756,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
         * Clear all tags associated with the just-deleted item
         */
        nr_cleared_tags = 0;
-       for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+       for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
                tags[tag] = 1;
                if (tag_get(pathp->node, tag, pathp->offset)) {
                        tag_clear(pathp->node, tag, pathp->offset);
@@ -763,7 +768,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
        }
 
        for (pathp--; nr_cleared_tags && pathp->node; pathp--) {
-               for (tag = 0; tag < RADIX_TREE_TAGS; tag++) {
+               for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
                        if (tags[tag])
                                continue;
 
@@ -801,7 +806,7 @@ EXPORT_SYMBOL(radix_tree_delete);
  *     @root:          radix tree root
  *     @tag:           tag to test
  */
-int radix_tree_tagged(struct radix_tree_root *root, int tag)
+int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag)
 {
        struct radix_tree_node *rnode;
        rnode = root->rnode;
index bd80460360db38a0b9d03dfefd087d6036c1b216..332f5c29b53a3c04665e4d727fc50dbfde609fb2 100644 (file)
@@ -138,8 +138,8 @@ config SPLIT_PTLOCK_CPUS
 #
 config MIGRATION
        bool "Page migration"
-       def_bool y if NUMA || SPARSEMEM || DISCONTIGMEM
-       depends on SWAP
+       def_bool y if NUMA
+       depends on SWAP && NUMA
        help
          Allows the migration of the physical location of pages of processes
          while the virtual addresses are not changed. This is useful for
index 0eb9894db6de6a0fa56caabbd1c002f0cea8e2c3..4f5b5709136abbe6c08b306ac35ac92740cb04d8 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1040,12 +1040,11 @@ munmap_back:
         * specific mapper. the address has already been validated, but
         * not unmapped, but the maps are removed from the list.
         */
-       vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+       vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
        if (!vma) {
                error = -ENOMEM;
                goto unacct_error;
        }
-       memset(vma, 0, sizeof(*vma));
 
        vma->vm_mm = mm;
        vma->vm_start = addr;
@@ -1896,12 +1895,11 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        /*
         * create a vma struct for an anonymous mapping
         */
-       vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+       vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
        if (!vma) {
                vm_unacct_memory(len >> PAGE_SHIFT);
                return -ENOMEM;
        }
-       memset(vma, 0, sizeof(*vma));
 
        vma->vm_mm = mm;
        vma->vm_start = addr;
index a5c3f8bd98ae4edb299966d618c719f47ca175ac..338a02bb004d3b3f37f49711ad05baaaa1e7d529 100644 (file)
@@ -2029,8 +2029,9 @@ static __meminit void zone_pcp_init(struct zone *zone)
                setup_pageset(zone_pcp(zone,cpu), batch);
 #endif
        }
-       printk(KERN_DEBUG "  %s zone: %lu pages, LIFO batch:%lu\n",
-               zone->name, zone->present_pages, batch);
+       if (zone->present_pages)
+               printk(KERN_DEBUG "  %s zone: %lu pages, LIFO batch:%lu\n",
+                       zone->name, zone->present_pages, batch);
 }
 
 static __meminit void init_currently_empty_zone(struct zone *zone,
@@ -2701,8 +2702,7 @@ void *__init alloc_large_system_hash(const char *tablename,
                else
                        numentries <<= (PAGE_SHIFT - scale);
        }
-       /* rounded up to nearest power of 2 in size */
-       numentries = 1UL << (long_log2(numentries) + 1);
+       numentries = roundup_pow_of_two(numentries);
 
        /* limit allocation size to 1/16 total memory by default */
        if (max == 0) {
index 26138c9f8f00906e638835baa46d5ebd7f602957..681837499d7d59fa967cd2297a250ceff6e278af 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
 typedef unsigned int kmem_bufctl_t;
 #define BUFCTL_END     (((kmem_bufctl_t)(~0U))-0)
 #define BUFCTL_FREE    (((kmem_bufctl_t)(~0U))-1)
-#define        SLAB_LIMIT      (((kmem_bufctl_t)(~0U))-2)
+#define        BUFCTL_ACTIVE   (((kmem_bufctl_t)(~0U))-2)
+#define        SLAB_LIMIT      (((kmem_bufctl_t)(~0U))-3)
 
 /* Max number of objs-per-slab for caches which use off-slab slabs.
  * Needed to avoid a possible looping condition in cache_grow().
@@ -897,6 +898,30 @@ static struct array_cache *alloc_arraycache(int node, int entries,
        return nc;
 }
 
+/*
+ * Transfer objects in one arraycache to another.
+ * Locking must be handled by the caller.
+ *
+ * Return the number of entries transferred.
+ */
+static int transfer_objects(struct array_cache *to,
+               struct array_cache *from, unsigned int max)
+{
+       /* Figure out how many entries to transfer */
+       int nr = min(min(from->avail, max), to->limit - to->avail);
+
+       if (!nr)
+               return 0;
+
+       memcpy(to->entry + to->avail, from->entry + from->avail -nr,
+                       sizeof(void *) *nr);
+
+       from->avail -= nr;
+       to->avail += nr;
+       to->touched = 1;
+       return nr;
+}
+
 #ifdef CONFIG_NUMA
 static void *__cache_alloc_node(struct kmem_cache *, gfp_t, int);
 static void *alternate_node_alloc(struct kmem_cache *, gfp_t);
@@ -946,6 +971,13 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
 
        if (ac->avail) {
                spin_lock(&rl3->list_lock);
+               /*
+                * Stuff objects into the remote nodes shared array first.
+                * That way we could avoid the overhead of putting the objects
+                * into the free lists and getting them back later.
+                */
+               transfer_objects(rl3->shared, ac, ac->limit);
+
                free_block(cachep, ac->entry, ac->avail, node);
                ac->avail = 0;
                spin_unlock(&rl3->list_lock);
@@ -961,8 +993,8 @@ static void reap_alien(struct kmem_cache *cachep, struct kmem_list3 *l3)
 
        if (l3->alien) {
                struct array_cache *ac = l3->alien[node];
-               if (ac && ac->avail) {
-                       spin_lock_irq(&ac->lock);
+
+               if (ac && ac->avail && spin_trylock_irq(&ac->lock)) {
                        __drain_alien_cache(cachep, ac, node);
                        spin_unlock_irq(&ac->lock);
                }
@@ -1989,10 +2021,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        align = ralign;
 
        /* Get cache's description obj. */
-       cachep = kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
+       cachep = kmem_cache_zalloc(&cache_cache, SLAB_KERNEL);
        if (!cachep)
                goto oops;
-       memset(cachep, 0, sizeof(struct kmem_cache));
 
 #if DEBUG
        cachep->obj_size = size;
@@ -2399,7 +2430,7 @@ static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp,
        /* Verify that the slab belongs to the intended node */
        WARN_ON(slabp->nodeid != nodeid);
 
-       if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
+       if (slab_bufctl(slabp)[objnr] + 1 <= SLAB_LIMIT + 1) {
                printk(KERN_ERR "slab: double free detected in cache "
                                "'%s', objp %p\n", cachep->name, objp);
                BUG();
@@ -2605,6 +2636,9 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
                 */
                cachep->dtor(objp + obj_offset(cachep), cachep, 0);
        }
+#ifdef CONFIG_DEBUG_SLAB_LEAK
+       slab_bufctl(slabp)[objnr] = BUFCTL_FREE;
+#endif
        if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
                if ((cachep->buffer_size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
@@ -2677,20 +2711,10 @@ retry:
        BUG_ON(ac->avail > 0 || !l3);
        spin_lock(&l3->list_lock);
 
-       if (l3->shared) {
-               struct array_cache *shared_array = l3->shared;
-               if (shared_array->avail) {
-                       if (batchcount > shared_array->avail)
-                               batchcount = shared_array->avail;
-                       shared_array->avail -= batchcount;
-                       ac->avail = batchcount;
-                       memcpy(ac->entry,
-                              &(shared_array->entry[shared_array->avail]),
-                              sizeof(void *) * batchcount);
-                       shared_array->touched = 1;
-                       goto alloc_done;
-               }
-       }
+       /* See if we can refill from the shared array */
+       if (l3->shared && transfer_objects(ac, l3->shared, batchcount))
+               goto alloc_done;
+
        while (batchcount > 0) {
                struct list_head *entry;
                struct slab *slabp;
@@ -2788,6 +2812,16 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
                *dbg_redzone1(cachep, objp) = RED_ACTIVE;
                *dbg_redzone2(cachep, objp) = RED_ACTIVE;
        }
+#ifdef CONFIG_DEBUG_SLAB_LEAK
+       {
+               struct slab *slabp;
+               unsigned objnr;
+
+               slabp = page_get_slab(virt_to_page(objp));
+               objnr = (unsigned)(objp - slabp->s_mem) / cachep->buffer_size;
+               slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
+       }
+#endif
        objp += obj_offset(cachep);
        if (cachep->ctor && cachep->flags & SLAB_POISON) {
                unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR;
@@ -3093,6 +3127,23 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 }
 EXPORT_SYMBOL(kmem_cache_alloc);
 
+/**
+ * kmem_cache_alloc - Allocate an object. The memory is set to zero.
+ * @cache: The cache to allocate from.
+ * @flags: See kmalloc().
+ *
+ * Allocate an object from this cache and set the allocated memory to zero.
+ * The flags are only relevant if the cache has no available objects.
+ */
+void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags)
+{
+       void *ret = __cache_alloc(cache, flags, __builtin_return_address(0));
+       if (ret)
+               memset(ret, 0, obj_size(cache));
+       return ret;
+}
+EXPORT_SYMBOL(kmem_cache_zalloc);
+
 /**
  * kmem_ptr_validate - check if an untrusted pointer might
  *     be a slab entry.
@@ -3220,22 +3271,23 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
        return __cache_alloc(cachep, flags, caller);
 }
 
-#ifndef CONFIG_DEBUG_SLAB
 
 void *__kmalloc(size_t size, gfp_t flags)
 {
+#ifndef CONFIG_DEBUG_SLAB
        return __do_kmalloc(size, flags, NULL);
+#else
+       return __do_kmalloc(size, flags, __builtin_return_address(0));
+#endif
 }
 EXPORT_SYMBOL(__kmalloc);
 
-#else
-
+#ifdef CONFIG_DEBUG_SLAB
 void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
 {
        return __do_kmalloc(size, flags, caller);
 }
 EXPORT_SYMBOL(__kmalloc_track_caller);
-
 #endif
 
 #ifdef CONFIG_SMP
@@ -3366,63 +3418,86 @@ const char *kmem_cache_name(struct kmem_cache *cachep)
 EXPORT_SYMBOL_GPL(kmem_cache_name);
 
 /*
- * This initializes kmem_list3 for all nodes.
+ * This initializes kmem_list3 or resizes varioius caches for all nodes.
  */
 static int alloc_kmemlist(struct kmem_cache *cachep)
 {
        int node;
        struct kmem_list3 *l3;
-       int err = 0;
+       struct array_cache *new_shared;
+       struct array_cache **new_alien;
 
        for_each_online_node(node) {
-               struct array_cache *nc = NULL, *new;
-               struct array_cache **new_alien = NULL;
-#ifdef CONFIG_NUMA
+
                new_alien = alloc_alien_cache(node, cachep->limit);
                if (!new_alien)
                        goto fail;
-#endif
-               new = alloc_arraycache(node, cachep->shared*cachep->batchcount,
+
+               new_shared = alloc_arraycache(node,
+                               cachep->shared*cachep->batchcount,
                                        0xbaadf00d);
-               if (!new)
+               if (!new_shared) {
+                       free_alien_cache(new_alien);
                        goto fail;
+               }
+
                l3 = cachep->nodelists[node];
                if (l3) {
+                       struct array_cache *shared = l3->shared;
+
                        spin_lock_irq(&l3->list_lock);
 
-                       nc = cachep->nodelists[node]->shared;
-                       if (nc)
-                               free_block(cachep, nc->entry, nc->avail, node);
+                       if (shared)
+                               free_block(cachep, shared->entry,
+                                               shared->avail, node);
 
-                       l3->shared = new;
-                       if (!cachep->nodelists[node]->alien) {
+                       l3->shared = new_shared;
+                       if (!l3->alien) {
                                l3->alien = new_alien;
                                new_alien = NULL;
                        }
                        l3->free_limit = (1 + nr_cpus_node(node)) *
                                        cachep->batchcount + cachep->num;
                        spin_unlock_irq(&l3->list_lock);
-                       kfree(nc);
+                       kfree(shared);
                        free_alien_cache(new_alien);
                        continue;
                }
                l3 = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, node);
-               if (!l3)
+               if (!l3) {
+                       free_alien_cache(new_alien);
+                       kfree(new_shared);
                        goto fail;
+               }
 
                kmem_list3_init(l3);
                l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
                                ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
-               l3->shared = new;
+               l3->shared = new_shared;
                l3->alien = new_alien;
                l3->free_limit = (1 + nr_cpus_node(node)) *
                                        cachep->batchcount + cachep->num;
                cachep->nodelists[node] = l3;
        }
-       return err;
+       return 0;
+
 fail:
-       err = -ENOMEM;
-       return err;
+       if (!cachep->next.next) {
+               /* Cache is not active yet. Roll back what we did */
+               node--;
+               while (node >= 0) {
+                       if (cachep->nodelists[node]) {
+                               l3 = cachep->nodelists[node];
+
+                               kfree(l3->shared);
+                               free_alien_cache(l3->alien);
+                               kfree(l3);
+                               cachep->nodelists[node] = NULL;
+                       }
+                       node--;
+               }
+       }
+       return -ENOMEM;
 }
 
 struct ccupdate_struct {
@@ -3899,6 +3974,159 @@ ssize_t slabinfo_write(struct file *file, const char __user * buffer,
                res = count;
        return res;
 }
+
+#ifdef CONFIG_DEBUG_SLAB_LEAK
+
+static void *leaks_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t n = *pos;
+       struct list_head *p;
+
+       mutex_lock(&cache_chain_mutex);
+       p = cache_chain.next;
+       while (n--) {
+               p = p->next;
+               if (p == &cache_chain)
+                       return NULL;
+       }
+       return list_entry(p, struct kmem_cache, next);
+}
+
+static inline int add_caller(unsigned long *n, unsigned long v)
+{
+       unsigned long *p;
+       int l;
+       if (!v)
+               return 1;
+       l = n[1];
+       p = n + 2;
+       while (l) {
+               int i = l/2;
+               unsigned long *q = p + 2 * i;
+               if (*q == v) {
+                       q[1]++;
+                       return 1;
+               }
+               if (*q > v) {
+                       l = i;
+               } else {
+                       p = q + 2;
+                       l -= i + 1;
+               }
+       }
+       if (++n[1] == n[0])
+               return 0;
+       memmove(p + 2, p, n[1] * 2 * sizeof(unsigned long) - ((void *)p - (void *)n));
+       p[0] = v;
+       p[1] = 1;
+       return 1;
+}
+
+static void handle_slab(unsigned long *n, struct kmem_cache *c, struct slab *s)
+{
+       void *p;
+       int i;
+       if (n[0] == n[1])
+               return;
+       for (i = 0, p = s->s_mem; i < c->num; i++, p += c->buffer_size) {
+               if (slab_bufctl(s)[i] != BUFCTL_ACTIVE)
+                       continue;
+               if (!add_caller(n, (unsigned long)*dbg_userword(c, p)))
+                       return;
+       }
+}
+
+static void show_symbol(struct seq_file *m, unsigned long address)
+{
+#ifdef CONFIG_KALLSYMS
+       char *modname;
+       const char *name;
+       unsigned long offset, size;
+       char namebuf[KSYM_NAME_LEN+1];
+
+       name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
+
+       if (name) {
+               seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
+               if (modname)
+                       seq_printf(m, " [%s]", modname);
+               return;
+       }
+#endif
+       seq_printf(m, "%p", (void *)address);
+}
+
+static int leaks_show(struct seq_file *m, void *p)
+{
+       struct kmem_cache *cachep = p;
+       struct list_head *q;
+       struct slab *slabp;
+       struct kmem_list3 *l3;
+       const char *name;
+       unsigned long *n = m->private;
+       int node;
+       int i;
+
+       if (!(cachep->flags & SLAB_STORE_USER))
+               return 0;
+       if (!(cachep->flags & SLAB_RED_ZONE))
+               return 0;
+
+       /* OK, we can do it */
+
+       n[1] = 0;
+
+       for_each_online_node(node) {
+               l3 = cachep->nodelists[node];
+               if (!l3)
+                       continue;
+
+               check_irq_on();
+               spin_lock_irq(&l3->list_lock);
+
+               list_for_each(q, &l3->slabs_full) {
+                       slabp = list_entry(q, struct slab, list);
+                       handle_slab(n, cachep, slabp);
+               }
+               list_for_each(q, &l3->slabs_partial) {
+                       slabp = list_entry(q, struct slab, list);
+                       handle_slab(n, cachep, slabp);
+               }
+               spin_unlock_irq(&l3->list_lock);
+       }
+       name = cachep->name;
+       if (n[0] == n[1]) {
+               /* Increase the buffer size */
+               mutex_unlock(&cache_chain_mutex);
+               m->private = kzalloc(n[0] * 4 * sizeof(unsigned long), GFP_KERNEL);
+               if (!m->private) {
+                       /* Too bad, we are really out */
+                       m->private = n;
+                       mutex_lock(&cache_chain_mutex);
+                       return -ENOMEM;
+               }
+               *(unsigned long *)m->private = n[0] * 2;
+               kfree(n);
+               mutex_lock(&cache_chain_mutex);
+               /* Now make sure this entry will be retried */
+               m->count = m->size;
+               return 0;
+       }
+       for (i = 0; i < n[1]; i++) {
+               seq_printf(m, "%s: %lu ", name, n[2*i+3]);
+               show_symbol(m, n[2*i+2]);
+               seq_putc(m, '\n');
+       }
+       return 0;
+}
+
+struct seq_operations slabstats_op = {
+       .start = leaks_start,
+       .next = s_next,
+       .stop = s_stop,
+       .show = leaks_show,
+};
+#endif
 #endif
 
 /**
index a1f42bdc0245c84889080f20be6abb42ac808add..9bcc7e2cabfd4d5b9147b8547a34e6dd0594a629 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -294,6 +294,16 @@ void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)
 }
 EXPORT_SYMBOL(kmem_cache_alloc);
 
+void *kmem_cache_zalloc(struct kmem_cache *c, gfp_t flags)
+{
+       void *ret = kmem_cache_alloc(c, flags);
+       if (ret)
+               memset(ret, 0, c->size);
+
+       return ret;
+}
+EXPORT_SYMBOL(kmem_cache_zalloc);
+
 void kmem_cache_free(struct kmem_cache *c, void *b)
 {
        if (c->dtor)
index 49e29f751b50316b47944efd4562dded42e5a2e9..7368479220b3b4c3d8c12a9306bb18221d9a99b9 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -5,18 +5,18 @@
 #include <asm/uaccess.h>
 
 /**
- * kzalloc - allocate memory. The memory is set to zero.
+ * __kzalloc - allocate memory. The memory is set to zero.
  * @size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
  */
-void *kzalloc(size_t size, gfp_t flags)
+void *__kzalloc(size_t size, gfp_t flags)
 {
-       void *ret = kmalloc(size, flags);
+       void *ret = ____kmalloc(size, flags);
        if (ret)
                memset(ret, 0, size);
        return ret;
 }
-EXPORT_SYMBOL(kzalloc);
+EXPORT_SYMBOL(__kzalloc);
 
 /*
  * kstrdup - allocate space for and copy an existing string
@@ -33,7 +33,7 @@ char *kstrdup(const char *s, gfp_t gfp)
                return NULL;
 
        len = strlen(s) + 1;
-       buf = kmalloc(len, gfp);
+       buf = ____kmalloc(len, gfp);
        if (buf)
                memcpy(buf, s, len);
        return buf;
index fd572bbdc9f5a67064b0c37e8790671657721875..78865c849f8fe712296fc18d2d7894d550f1fc85 100644 (file)
@@ -1356,7 +1356,9 @@ static int __init kswapd_init(void)
 
                pid = kernel_thread(kswapd, pgdat, CLONE_KERNEL);
                BUG_ON(pid < 0);
+               read_lock(&tasklist_lock);
                pgdat->kswapd = find_task_by_pid(pid);
+               read_unlock(&tasklist_lock);
        }
        total_memory = nr_free_pagecache_pages();
        hotcpu_notifier(cpu_callback, 0);
index fb031fe9be9ed140bce6fdfe6092f3ab6df8ff87..469eda0f0dfd713f0d998b5c830faaff2e9c71fd 100644 (file)
@@ -238,6 +238,9 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
+
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
index 8934a54792be48d91b7edbc0d37ff654711b1640..a7ba0cce0b4658738e170a5ee2d11ed64414c407 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/llc.h>
 #include <net/llc.h>
 #include <net/llc_pdu.h>
+#include <asm/unaligned.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
@@ -59,12 +60,12 @@ static inline void br_set_ticks(unsigned char *dest, int j)
 {
        unsigned long ticks = (STP_HZ * j)/ HZ;
 
-       *((__be16 *) dest) = htons(ticks);
+       put_unaligned(htons(ticks), (__be16 *)dest);
 }
 
 static inline int br_get_ticks(const unsigned char *src)
 {
-       unsigned long ticks = ntohs(*(__be16 *)src);
+       unsigned long ticks = ntohs(get_unaligned((__be16 *)src));
 
        return (ticks * HZ + STP_HZ - 1) / STP_HZ;
 }
index b8ce6bf81188943a1ac91f3b80b361d03ce3c955..aecddcc304012d48769e9f98b91157aa946cd60d 100644 (file)
@@ -500,6 +500,8 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        /* exceptional events? */
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
index 08dec6eb922bc6c971f952c4c396bf23e7c7d292..e0489ca731c57f17dda1ce30cfc7747098c4e221 100644 (file)
@@ -977,7 +977,12 @@ int register_netdevice_notifier(struct notifier_block *nb)
 
 int unregister_netdevice_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_unregister(&netdev_chain, nb);
+       int err;
+
+       rtnl_lock();
+       err = notifier_chain_unregister(&netdev_chain, nb);
+       rtnl_unlock();
+       return err;
 }
 
 /**
index c9f8784545314962b87f19cb80153652c178a42e..09464fa8d72f8b10c881b44678e8aa1084a3bcfb 100644 (file)
@@ -149,7 +149,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
 
        /* Get the DATA. Size must match skb_add_mtu(). */
        size = SKB_DATA_ALIGN(size);
-       data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+       data = ____kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
        if (!data)
                goto nodata;
 
index 1a7e6eac90b04f89efca8620ed64686496a8e647..e110b9004147b4418391467a4b31715a5dc2902a 100644 (file)
@@ -404,8 +404,9 @@ set_rcvbuf:
                        if (!valbool) {
                                sk->sk_bound_dev_if = 0;
                        } else {
-                               if (optlen > IFNAMSIZ) 
-                                       optlen = IFNAMSIZ; 
+                               if (optlen > IFNAMSIZ - 1)
+                                       optlen = IFNAMSIZ - 1;
+                               memset(devname, 0, sizeof(devname));
                                if (copy_from_user(devname, optval, optlen)) {
                                        ret = -EFAULT;
                                        break;
index d4b293e16283e4e2e5ddc3b5b25fb84c2aecc05b..1ff7328b0e170bf137819ab03a76b3a4acdd9572 100644 (file)
@@ -350,7 +350,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
        if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
                mask |= POLLHUP;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLIN | POLLRDNORM;
+               mask |= POLLIN | POLLRDNORM | POLLRDHUP;
 
        /* Connected? */
        if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
index e7bbff4340bb6c2d73c956b15c40a4b596296ecb..9831fd2c73a0a222290f504e44d413627c5fe216 100644 (file)
@@ -753,7 +753,7 @@ static void icmp_redirect(struct sk_buff *skb)
        case ICMP_REDIR_HOST:
        case ICMP_REDIR_HOSTTOS:
                ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway,
-                              iph->saddr, iph->tos, skb->dev);
+                              iph->saddr, skb->dev);
                break;
        }
 out:
index fca5fe0cf94a397fe957f26a39ebd82054f9582c..94fcbc5e5a1b62cfd696a6751dfcd17816a74f4a 100644 (file)
@@ -55,6 +55,8 @@
  *     Robert Olsson           :       Added rt_cache statistics
  *     Arnaldo C. Melo         :       Convert proc stuff to seq_file
  *     Eric Dumazet            :       hashed spinlocks and rt_check_expire() fixes.
+ *     Ilia Sotnikov           :       Ignore TOS on PMTUD and Redirect
+ *     Ilia Sotnikov           :       Removed TOS from hash calculations
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -247,9 +249,9 @@ static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
 static int rt_intern_hash(unsigned hash, struct rtable *rth,
                                struct rtable **res);
 
-static unsigned int rt_hash_code(u32 daddr, u32 saddr, u8 tos)
+static unsigned int rt_hash_code(u32 daddr, u32 saddr)
 {
-       return (jhash_3words(daddr, saddr, (u32) tos, rt_hash_rnd)
+       return (jhash_2words(daddr, saddr, rt_hash_rnd)
                & rt_hash_mask);
 }
 
@@ -1111,7 +1113,7 @@ static void rt_del(unsigned hash, struct rtable *rt)
 }
 
 void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
-                   u32 saddr, u8 tos, struct net_device *dev)
+                   u32 saddr, struct net_device *dev)
 {
        int i, k;
        struct in_device *in_dev = in_dev_get(dev);
@@ -1119,8 +1121,6 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
        u32  skeys[2] = { saddr, 0 };
        int  ikeys[2] = { dev->ifindex, 0 };
 
-       tos &= IPTOS_RT_MASK;
-
        if (!in_dev)
                return;
 
@@ -1141,8 +1141,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
        for (i = 0; i < 2; i++) {
                for (k = 0; k < 2; k++) {
                        unsigned hash = rt_hash_code(daddr,
-                                                    skeys[i] ^ (ikeys[k] << 5),
-                                                    tos);
+                                                    skeys[i] ^ (ikeys[k] << 5));
 
                        rthp=&rt_hash_table[hash].chain;
 
@@ -1152,7 +1151,6 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
 
                                if (rth->fl.fl4_dst != daddr ||
                                    rth->fl.fl4_src != skeys[i] ||
-                                   rth->fl.fl4_tos != tos ||
                                    rth->fl.oif != ikeys[k] ||
                                    rth->fl.iif != 0) {
                                        rthp = &rth->u.rt_next;
@@ -1232,10 +1230,9 @@ reject_redirect:
        if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
                printk(KERN_INFO "Redirect from %u.%u.%u.%u on %s about "
                        "%u.%u.%u.%u ignored.\n"
-                       "  Advised path = %u.%u.%u.%u -> %u.%u.%u.%u, "
-                       "tos %02x\n",
+                       "  Advised path = %u.%u.%u.%u -> %u.%u.%u.%u\n",
                       NIPQUAD(old_gw), dev->name, NIPQUAD(new_gw),
-                      NIPQUAD(saddr), NIPQUAD(daddr), tos);
+                      NIPQUAD(saddr), NIPQUAD(daddr));
 #endif
        in_dev_put(in_dev);
 }
@@ -1253,8 +1250,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
                           rt->u.dst.expires) {
                        unsigned hash = rt_hash_code(rt->fl.fl4_dst,
                                                     rt->fl.fl4_src ^
-                                                       (rt->fl.oif << 5),
-                                                    rt->fl.fl4_tos);
+                                                       (rt->fl.oif << 5));
 #if RT_CACHE_DEBUG >= 1
                        printk(KERN_DEBUG "ip_rt_advice: redirect to "
                                          "%u.%u.%u.%u/%02x dropped\n",
@@ -1391,14 +1387,13 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
        struct rtable *rth;
        u32  skeys[2] = { iph->saddr, 0, };
        u32  daddr = iph->daddr;
-       u8   tos = iph->tos & IPTOS_RT_MASK;
        unsigned short est_mtu = 0;
 
        if (ipv4_config.no_pmtu_disc)
                return 0;
 
        for (i = 0; i < 2; i++) {
-               unsigned hash = rt_hash_code(daddr, skeys[i], tos);
+               unsigned hash = rt_hash_code(daddr, skeys[i]);
 
                rcu_read_lock();
                for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -1407,7 +1402,6 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
                            rth->fl.fl4_src == skeys[i] &&
                            rth->rt_dst  == daddr &&
                            rth->rt_src  == iph->saddr &&
-                           rth->fl.fl4_tos == tos &&
                            rth->fl.iif == 0 &&
                            !(dst_metric_locked(&rth->u.dst, RTAX_MTU))) {
                                unsigned short mtu = new_mtu;
@@ -1658,7 +1652,7 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
        RT_CACHE_STAT_INC(in_slow_mc);
 
        in_dev_put(in_dev);
-       hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
+       hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5));
        return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
 
 e_nobufs:
@@ -1823,7 +1817,7 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
                return err;
 
        /* put it into the cache */
-       hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+       hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
        return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);   
 }
 
@@ -1864,7 +1858,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
                        return err;
 
                /* put it into the cache */
-               hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
+               hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
                err = rt_intern_hash(hash, rth, &rtres);
                if (err)
                        return err;
@@ -2041,7 +2035,7 @@ local_input:
                rth->rt_flags   &= ~RTCF_LOCAL;
        }
        rth->rt_type    = res.type;
-       hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
+       hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5));
        err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
        goto done;
 
@@ -2088,7 +2082,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
        int iif = dev->ifindex;
 
        tos &= IPTOS_RT_MASK;
-       hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos);
+       hash = rt_hash_code(daddr, saddr ^ (iif << 5));
 
        rcu_read_lock();
        for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -2286,10 +2280,8 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
        int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
        unsigned hash;
        if (err == 0) {
-               u32 tos = RT_FL_TOS(oldflp);
-
                hash = rt_hash_code(oldflp->fl4_dst, 
-                                   oldflp->fl4_src ^ (oldflp->oif << 5), tos);
+                                   oldflp->fl4_src ^ (oldflp->oif << 5));
                err = rt_intern_hash(hash, rth, rp);
        }
        
@@ -2304,7 +2296,6 @@ static inline int ip_mkroute_output(struct rtable** rp,
                                    unsigned flags)
 {
 #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
-       u32 tos = RT_FL_TOS(oldflp);
        unsigned char hop;
        unsigned hash;
        int err = -EINVAL;
@@ -2334,7 +2325,7 @@ static inline int ip_mkroute_output(struct rtable** rp,
 
                        hash = rt_hash_code(oldflp->fl4_dst, 
                                            oldflp->fl4_src ^
-                                           (oldflp->oif << 5), tos);
+                                           (oldflp->oif << 5));
                        err = rt_intern_hash(hash, rth, rp);
 
                        /* forward hop information to multipath impl. */
@@ -2563,7 +2554,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
        unsigned hash;
        struct rtable *rth;
 
-       hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos);
+       hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5));
 
        rcu_read_lock_bh();
        for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
index 4b0272c92d665a3b8b1caef5e4ed7d2526e06bb4..87f68e787d0c62d0d1fcd8ee53566c0a4a8467bd 100644 (file)
 #include <linux/fs.h>
 #include <linux/random.h>
 #include <linux/bootmem.h>
+#include <linux/cache.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -275,9 +276,9 @@ atomic_t tcp_orphan_count = ATOMIC_INIT(0);
 
 EXPORT_SYMBOL_GPL(tcp_orphan_count);
 
-int sysctl_tcp_mem[3];
-int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
-int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
+int sysctl_tcp_mem[3] __read_mostly;
+int sysctl_tcp_wmem[3] __read_mostly;
+int sysctl_tcp_rmem[3] __read_mostly;
 
 EXPORT_SYMBOL(sysctl_tcp_mem);
 EXPORT_SYMBOL(sysctl_tcp_rmem);
@@ -365,7 +366,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
        if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
                mask |= POLLHUP;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLIN | POLLRDNORM;
+               mask |= POLLIN | POLLRDNORM | POLLRDHUP;
 
        /* Connected? */
        if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
@@ -2081,7 +2082,8 @@ __setup("thash_entries=", set_thash_entries);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
-       int order, i;
+       unsigned long limit;
+       int order, i, max_share;
 
        if (sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
                __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -2155,12 +2157,16 @@ void __init tcp_init(void)
        sysctl_tcp_mem[1] = 1024 << order;
        sysctl_tcp_mem[2] = 1536 << order;
 
-       if (order < 3) {
-               sysctl_tcp_wmem[2] = 64 * 1024;
-               sysctl_tcp_rmem[0] = PAGE_SIZE;
-               sysctl_tcp_rmem[1] = 43689;
-               sysctl_tcp_rmem[2] = 2 * 43689;
-       }
+       limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
+       max_share = min(4UL*1024*1024, limit);
+
+       sysctl_tcp_wmem[0] = SK_STREAM_MEM_QUANTUM;
+       sysctl_tcp_wmem[1] = 16*1024;
+       sysctl_tcp_wmem[2] = max(64*1024, max_share);
+
+       sysctl_tcp_rmem[0] = SK_STREAM_MEM_QUANTUM;
+       sysctl_tcp_rmem[1] = 87380;
+       sysctl_tcp_rmem[2] = max(87380, max_share);
 
        printk(KERN_INFO "TCP: Hash tables configured "
               "(established %d bind %d)\n",
index 0a29a24d9a72f8344e88f509254cca4845018dbc..a657ab5394c3555f389cd7a81104f681b8621967 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
+#include <linux/mutex.h>
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_arp.h>
 
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
@@ -32,7 +34,7 @@ MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
 struct xt_af {
-       struct semaphore mutex;
+       struct mutex mutex;
        struct list_head match;
        struct list_head target;
        struct list_head tables;
@@ -64,11 +66,11 @@ xt_register_target(struct xt_target *target)
 {
        int ret, af = target->family;
 
-       ret = down_interruptible(&xt[af].mutex);
+       ret = mutex_lock_interruptible(&xt[af].mutex);
        if (ret != 0)
                return ret;
        list_add(&target->list, &xt[af].target);
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
        return ret;
 }
 EXPORT_SYMBOL(xt_register_target);
@@ -78,9 +80,9 @@ xt_unregister_target(struct xt_target *target)
 {
        int af = target->family;
 
-       down(&xt[af].mutex);
+       mutex_lock(&xt[af].mutex);
        LIST_DELETE(&xt[af].target, target);
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
 }
 EXPORT_SYMBOL(xt_unregister_target);
 
@@ -89,12 +91,12 @@ xt_register_match(struct xt_match *match)
 {
        int ret, af = match->family;
 
-       ret = down_interruptible(&xt[af].mutex);
+       ret = mutex_lock_interruptible(&xt[af].mutex);
        if (ret != 0)
                return ret;
 
        list_add(&match->list, &xt[af].match);
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
 
        return ret;
 }
@@ -105,9 +107,9 @@ xt_unregister_match(struct xt_match *match)
 {
        int af =  match->family;
 
-       down(&xt[af].mutex);
+       mutex_lock(&xt[af].mutex);
        LIST_DELETE(&xt[af].match, match);
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
 }
 EXPORT_SYMBOL(xt_unregister_match);
 
@@ -124,21 +126,21 @@ struct xt_match *xt_find_match(int af, const char *name, u8 revision)
        struct xt_match *m;
        int err = 0;
 
-       if (down_interruptible(&xt[af].mutex) != 0)
+       if (mutex_lock_interruptible(&xt[af].mutex) != 0)
                return ERR_PTR(-EINTR);
 
        list_for_each_entry(m, &xt[af].match, list) {
                if (strcmp(m->name, name) == 0) {
                        if (m->revision == revision) {
                                if (try_module_get(m->me)) {
-                                       up(&xt[af].mutex);
+                                       mutex_unlock(&xt[af].mutex);
                                        return m;
                                }
                        } else
                                err = -EPROTOTYPE; /* Found something. */
                }
        }
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_match);
@@ -149,21 +151,21 @@ struct xt_target *xt_find_target(int af, const char *name, u8 revision)
        struct xt_target *t;
        int err = 0;
 
-       if (down_interruptible(&xt[af].mutex) != 0)
+       if (mutex_lock_interruptible(&xt[af].mutex) != 0)
                return ERR_PTR(-EINTR);
 
        list_for_each_entry(t, &xt[af].target, list) {
                if (strcmp(t->name, name) == 0) {
                        if (t->revision == revision) {
                                if (try_module_get(t->me)) {
-                                       up(&xt[af].mutex);
+                                       mutex_unlock(&xt[af].mutex);
                                        return t;
                                }
                        } else
                                err = -EPROTOTYPE; /* Found something. */
                }
        }
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL(xt_find_target);
@@ -218,7 +220,7 @@ int xt_find_revision(int af, const char *name, u8 revision, int target,
 {
        int have_rev, best = -1;
 
-       if (down_interruptible(&xt[af].mutex) != 0) {
+       if (mutex_lock_interruptible(&xt[af].mutex) != 0) {
                *err = -EINTR;
                return 1;
        }
@@ -226,7 +228,7 @@ int xt_find_revision(int af, const char *name, u8 revision, int target,
                have_rev = target_revfn(af, name, revision, &best);
        else
                have_rev = match_revfn(af, name, revision, &best);
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
 
        /* Nothing at all?  Return 0 to try loading module. */
        if (best == -1) {
@@ -352,20 +354,20 @@ struct xt_table *xt_find_table_lock(int af, const char *name)
 {
        struct xt_table *t;
 
-       if (down_interruptible(&xt[af].mutex) != 0)
+       if (mutex_lock_interruptible(&xt[af].mutex) != 0)
                return ERR_PTR(-EINTR);
 
        list_for_each_entry(t, &xt[af].tables, list)
                if (strcmp(t->name, name) == 0 && try_module_get(t->me))
                        return t;
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
        return NULL;
 }
 EXPORT_SYMBOL_GPL(xt_find_table_lock);
 
 void xt_table_unlock(struct xt_table *table)
 {
-       up(&xt[table->af].mutex);
+       mutex_unlock(&xt[table->af].mutex);
 }
 EXPORT_SYMBOL_GPL(xt_table_unlock);
 
@@ -405,7 +407,7 @@ int xt_register_table(struct xt_table *table,
        int ret;
        struct xt_table_info *private;
 
-       ret = down_interruptible(&xt[table->af].mutex);
+       ret = mutex_lock_interruptible(&xt[table->af].mutex);
        if (ret != 0)
                return ret;
 
@@ -431,7 +433,7 @@ int xt_register_table(struct xt_table *table,
 
        ret = 0;
  unlock:
-       up(&xt[table->af].mutex);
+       mutex_unlock(&xt[table->af].mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(xt_register_table);
@@ -440,10 +442,10 @@ void *xt_unregister_table(struct xt_table *table)
 {
        struct xt_table_info *private;
 
-       down(&xt[table->af].mutex);
+       mutex_lock(&xt[table->af].mutex);
        private = table->private;
        LIST_DELETE(&xt[table->af].tables, table);
-       up(&xt[table->af].mutex);
+       mutex_unlock(&xt[table->af].mutex);
 
        return private;
 }
@@ -507,7 +509,7 @@ static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
        if (!list)
                return NULL;
 
-       if (down_interruptible(&xt[af].mutex) != 0)
+       if (mutex_lock_interruptible(&xt[af].mutex) != 0)
                return NULL;
        
        return xt_get_idx(list, seq, *pos);
@@ -536,7 +538,7 @@ static void xt_tgt_seq_stop(struct seq_file *seq, void *v)
        struct proc_dir_entry *pde = seq->private;
        u_int16_t af = (unsigned long)pde->data & 0xffff;
 
-       up(&xt[af].mutex);
+       mutex_unlock(&xt[af].mutex);
 }
 
 static int xt_name_seq_show(struct seq_file *seq, void *v)
@@ -668,7 +670,7 @@ static int __init xt_init(void)
                return -ENOMEM;
 
        for (i = 0; i < NPROTO; i++) {
-               init_MUTEX(&xt[i].mutex);
+               mutex_init(&xt[i].mutex);
                INIT_LIST_HEAD(&xt[i].target);
                INIT_LIST_HEAD(&xt[i].match);
                INIT_LIST_HEAD(&xt[i].tables);
index 36fdcbcd80d1fe0e9bf62c13a9ecf68cc0299b4a..48cbd065bb45ab8ba5d676f802ebbcdf2ecc0d28 100644 (file)
@@ -79,8 +79,8 @@ static int __init rxrpc_initialise(void)
  error_sysctl:
 #ifdef CONFIG_SYSCTL
        rxrpc_sysctl_cleanup();
-#endif
  error_proc:
+#endif
 #ifdef CONFIG_PROC_FS
        rxrpc_proc_cleanup();
 #endif
index cb78b50868eee0c765884565dbdc4b6d4c2df01b..d117ebc75cf87ce25aa8699f61b4338b12fc1053 100644 (file)
@@ -127,7 +127,6 @@ int sctp_rcv(struct sk_buff *skb)
        union sctp_addr dest;
        int family;
        struct sctp_af *af;
-       int ret = 0;
 
        if (skb->pkt_type!=PACKET_HOST)
                goto discard_it;
@@ -227,16 +226,13 @@ int sctp_rcv(struct sk_buff *skb)
                goto discard_release;
        nf_reset(skb);
 
-       ret = sk_filter(sk, skb, 1);
-       if (ret)
+       if (sk_filter(sk, skb, 1))
                 goto discard_release;
 
        /* Create an SCTP packet structure. */
        chunk = sctp_chunkify(skb, asoc, sk);
-       if (!chunk) {
-               ret = -ENOMEM;
+       if (!chunk)
                goto discard_release;
-       }
        SCTP_INPUT_CB(skb)->chunk = chunk;
 
        /* Remember what endpoint is to handle this packet. */
@@ -277,11 +273,11 @@ int sctp_rcv(struct sk_buff *skb)
        sctp_bh_unlock_sock(sk);
        sock_put(sk);
 
-       return ret;
+       return 0;
 
 discard_it:
        kfree_skb(skb);
-       return ret;
+       return 0;
 
 discard_release:
        /* Release any structures we may be holding. */
index 0ea947eb681320561d3e3d61ac91001aa1043926..b6e4b89539b3178216037c53350f5591dde8a1b6 100644 (file)
@@ -4894,6 +4894,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        /* Is there any exceptional events?  */
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
index 2b4cc2eea5b38bd6a686b94cb0136f8b7a18adbf..d901465ce0135093276d55adabbb7691591097c3 100644 (file)
@@ -1878,6 +1878,8 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl
                mask |= POLLERR;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
 
        /* readable? */
        if (!skb_queue_empty(&sk->sk_receive_queue) ||
index d591578bd3b209ab8258a814b30727366e8909d8..22d281c6ec244c16bb0dc1c870e7f5c5ce913fb5 100644 (file)
@@ -124,6 +124,11 @@ static int read_symbol(FILE *in, struct sym_entry *s)
         * compressed together */
        s->len = strlen(str) + 1;
        s->sym = malloc(s->len + 1);
+       if (!s->sym) {
+               fprintf(stderr, "kallsyms failure: "
+                       "unable to allocate required amount of memory\n");
+               exit(EXIT_FAILURE);
+       }
        strcpy((char *)s->sym + 1, str);
        s->sym[0] = stype;
 
@@ -272,7 +277,12 @@ static void write_src(void)
 
        /* table of offset markers, that give the offset in the compressed stream
         * every 256 symbols */
-       markers = (unsigned int *) malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
+       markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
+       if (!markers) {
+               fprintf(stderr, "kallsyms failure: "
+                       "unable to allocate required memory\n");
+               exit(EXIT_FAILURE);
+       }
 
        output_label("kallsyms_names");
        off = 0;
index 8a6e097f99ea677acf091800f4bd3797975f9f75..841eb4e5c62b6e91b0e799802791289366bfb45d 100644 (file)
@@ -60,8 +60,8 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
 int cap_ptrace (struct task_struct *parent, struct task_struct *child)
 {
        /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
-       if (!cap_issubset (child->cap_permitted, current->cap_permitted) &&
-           !capable(CAP_SYS_PTRACE))
+       if (!cap_issubset(child->cap_permitted, parent->cap_permitted) &&
+           !__capable(parent, CAP_SYS_PTRACE))
                return -EPERM;
        return 0;
 }
index 99781b798312f0da18bd7063aa9b7856f7fe48fa..a057e3311aad662f1ebcd8e79919fe76ea947e4b 100644 (file)
@@ -1,6 +1,6 @@
 /* key.c: basic authentication token and access key management
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -271,7 +271,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
         * its description */
        if (!not_in_quota) {
                spin_lock(&user->lock);
-               if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS &&
+               if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
                    user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
                    )
                        goto no_quota;
@@ -795,12 +795,16 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                goto error_3;
        }
 
-       /* search for an existing key of the same type and description in the
-        * destination keyring
+       /* if it's possible to update this type of key, search for an existing
+        * key of the same type and description in the destination keyring and
+        * update that instead if possible
         */
-       key_ref = __keyring_search_one(keyring_ref, ktype, description, 0);
-       if (!IS_ERR(key_ref))
-               goto found_matching_key;
+       if (ktype->update) {
+               key_ref = __keyring_search_one(keyring_ref, ktype, description,
+                                              0);
+               if (!IS_ERR(key_ref))
+                       goto found_matching_key;
+       }
 
        /* decide on the permissions we want */
        perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
index f693e1f66b98521c3c6e0995a5c6182935b1b18a..51ef509710b9d50bc7aa65d89cbf7bde359a6126 100644 (file)
@@ -174,31 +174,8 @@ int mod_unreg_security(const char *name, struct security_operations *ops)
        return security_ops->unregister_security(name, ops);
 }
 
-/**
- * capable - calls the currently loaded security module's capable() function with the specified capability
- * @cap: the requested capability level.
- *
- * This function calls the currently loaded security module's capable()
- * function with a pointer to the current task and the specified @cap value.
- *
- * This allows the security module to implement the capable function call
- * however it chooses to.
- */
-int capable(int cap)
-{
-       if (security_ops->capable(current, cap)) {
-               /* capability denied */
-               return 0;
-       }
-
-       /* capability granted */
-       current->flags |= PF_SUPERPRIV;
-       return 1;
-}
-
 EXPORT_SYMBOL_GPL(register_security);
 EXPORT_SYMBOL_GPL(unregister_security);
 EXPORT_SYMBOL_GPL(mod_reg_security);
 EXPORT_SYMBOL_GPL(mod_unreg_security);
-EXPORT_SYMBOL(capable);
 EXPORT_SYMBOL(security_ops);
index fe54de25aafc400b2fbb60117b125c79b1385658..eacb0aef21e1831d6795225aba3b6d6cc00c46e4 100644 (file)
 
 /* Boot options */
 static int      vra = 0;       // 0 = no VRA, 1 = use VRA if codec supports it
-MODULE_PARM(vra, "i");
+module_param(vra, bool, 0);
 MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
 
 
index 6a4956b8025df671e4ce94ebbec9ad533f8bc834..c1168fae6be63666f20f561fc2fd5ca6cb46795e 100644 (file)
@@ -79,7 +79,7 @@
  * 0 = no VRA, 1 = use VRA if codec supports it
  */
 static int      vra = 1;
-MODULE_PARM(vra, "i");
+module_param(vra, bool, 0);
 MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
 
 static struct au1550_state {
index b3ea719d33db0b737a6fb64c5d7d311b14014f99..d1a0eb294d6f64c2b45aac340fb05ae0ba913429 100644 (file)
@@ -2944,7 +2944,7 @@ alloc_new_info(void)
 {
        awe_voice_list *newlist;
        
-       newlist = (awe_voice_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
+       newlist = kmalloc(sizeof(*newlist), GFP_KERNEL);
        if (newlist == NULL) {
                printk(KERN_ERR "AWE32: can't alloc info table\n");
                return NULL;
@@ -3547,8 +3547,10 @@ awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag)
        smp->checksum_flag = 0;
        smp->checksum = 0;
 
-       if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0)
+       if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) {
+               kfree(vrec);
                return rc;
+       }
        sf->mem_ptr += rc;
        add_sf_sample(sf, smprec);
 
index c9302a1e515ba98201d268e4202905b0247d5bdc..87bd3100aef3800cb9da9d56a25132c64d23aeef 100644 (file)
      */
 
 int dmasound_catchRadius = 0;
-MODULE_PARM(dmasound_catchRadius, "i");
+module_param(dmasound_catchRadius, int, 0);
 
 static unsigned int numWriteBufs = DEFAULT_N_BUFFERS;
-MODULE_PARM(numWriteBufs, "i");
+module_param(numWriteBufs, int, 0);
 static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */
-MODULE_PARM(writeBufSize, "i");
+module_param(writeBufSize, int, 0);
 
 #ifdef HAS_RECORD
 static unsigned int numReadBufs = DEFAULT_N_BUFFERS;
-MODULE_PARM(numReadBufs, "i");
+module_param(numReadBufs, int, 0);
 static unsigned int readBufSize = DEFAULT_BUFF_SIZE;   /* in bytes */
-MODULE_PARM(readBufSize, "i");
+module_param(readBufSize, int, 0);
 #endif
 
 MODULE_LICENSE("GPL");
index ffcb910f5c3e16637b9afa6811a52db1b6544dfb..00ac1c95a4290b0e20ac19cb779f4166ce0930b9 100644 (file)
@@ -1968,9 +1968,9 @@ static int i2s_fmt[NR_DEVICE];
 
 static unsigned int devindex;
 
-MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i");
+module_param_array(spdif, int, NULL, 0);
 MODULE_PARM_DESC(spdif, "if 1 the S/PDIF digital output is enabled");
-MODULE_PARM(i2s_fmt, "1-" __MODULE_STRING(NR_DEVICE) "i");
+module_param_array(i2s_fmt, int, NULL, 0);
 MODULE_PARM_DESC(i2s_fmt, "the format of I2S");
 
 MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com");
index f56898c3981e0031f8073e885276876a4e30de8f..ccb21d48d42c5f4c41208e7fb767220a95d18c99 100644 (file)
@@ -273,14 +273,14 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right)
        int regoffs;
        unsigned char val;
 
+       if ((dev < 0) || (dev >= devc->iomap_sz))
+               return -EINVAL;
+
        regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
 
        if (regoffs == 0)
                return -EINVAL;
 
-       if ((dev < 0) || (dev >= devc->iomap_sz))
-           return -EINVAL;
-
        val = sb_getmixer(devc, regoffs);
        change_bits(devc, &val, dev, LEFT_CHN, left);
 
index 698614226c9adf5e8ac2c8976b44884855cd4817..347cd79c2502aa23b5af9ad62b4f81ce32cfb705 100644 (file)
@@ -709,11 +709,11 @@ static void seq_local_event(unsigned char *event_rec)
 
 static void seq_sysex_message(unsigned char *event_rec)
 {
-       int dev = event_rec[1];
+       unsigned int dev = event_rec[1];
        int i, l = 0;
        unsigned char  *buf = &event_rec[2];
 
-       if ((int) dev > max_synthdev)
+       if (dev > max_synthdev)
                return;
        if (!(synth_open_mask & (1 << dev)))
                return;
index dce9016cbcfde2ee55d8de79784daedc31670306..eb5ea32fd1b0ffde2b44b75413664323eaf7f04a 100644 (file)
@@ -154,8 +154,8 @@ static void start_adc(struct cs4297a_state *s);
 #if CSDEBUG
 static unsigned long cs_debuglevel = 4;        // levels range from 1-9
 static unsigned long cs_debugmask = CS_INIT /*| CS_IOCTL*/;
-MODULE_PARM(cs_debuglevel, "i");
-MODULE_PARM(cs_debugmask, "i");
+module_param(cs_debuglevel, int, 0);
+module_param(cs_debugmask, int, 0);
 #endif
 #define CS_TRUE        1
 #define CS_FALSE       0
index 99d04ad3ca13158f4281e0c449c3d6a39e12be9d..afcb524a40eb52ce4fbd83080a3f25330d3b32f9 100644 (file)
@@ -2028,8 +2028,8 @@ __setup("waveartist=", setup_waveartist);
 #endif
 
 MODULE_DESCRIPTION("Rockwell WaveArtist RWA-010 sound driver");
-MODULE_PARM(io, "i");          /* IO base */
-MODULE_PARM(irq, "i");         /* IRQ */
-MODULE_PARM(dma, "i");         /* DMA */
-MODULE_PARM(dma2, "i");                /* DMA2 */
+module_param(io, int, 0);              /* IO base */
+module_param(irq, int, 0);             /* IRQ */
+module_param(dma, int, 0);             /* DMA */
+module_param(dma2, int, 0);            /* DMA2 */
 MODULE_LICENSE("GPL");